;//////////////////////////////////////////////////////////////
;//
;// NASMX Preprocessor
;// Copyright (c) 2005-2014, The NASMX Project
;//
%ifndef __NASMX_INCLUDED__
%define __NASMX_INCLUDED__

;//////////////////////////////////////////////////////////////
;//
;// Check NASM Version
;//
%define __nxerrmsg "NASM v2.11 or later required"
%ifdef __NASM_VERSION_ID__
	%if __NASM_VERSION_ID__ < 0x020B0000
		%fatal __nxerrmsg
	%endif
%else
	%fatal __nxerrmsg
%endif
%undef __nxerrmsg

;//////////////////////////////////////////////////////////////
;//
;// Set a NASMX Definition
;//
%macro NASMX_DEFINE 1-2.nolist
	%if %0 > 1
		%ixdefine __NASMX_%[%1]__ %[2]
	%else
		%ixdefine __NASMX_%[%1]__
	%endif
%endmacro


;//////////////////////////////////////////////////////////////
;//
;// Get a NASMX Definition
;//
%macro NASMX_GET_DEFINE 2.nolist
	%ifdef __NASMX_%[%1]__
		%xdefine %[%2] __NASMX_%[%1]__
	%elifdef %2
		%undef %[%2]
	%endif
%endmacro

;//////////////////////////////////////////////////////////////
;//
;// Undefine a NASMX Definition
;//
%macro NASMX_UNDEF 1.nolist
	%ifdef __NASMX_%[%1]__
		%undef __NASMX_%[%1]__
	%else
		%warning NASMX Definition %[1] is not defined
	%endif
%endmacro


;//////////////////////////////////////////////////////////////
;//
;// Define NASMX Version
;//
NASMX_DEFINE VERSION,"1.4"
NASMX_DEFINE VERSION_MAJOR, 1
NASMX_DEFINE VERSION_MINOR, 4
NASMX_DEFINE VERSION_REV, 16
NASMX_DEFINE VERSION_ID, 0x01040010


;//////////////////////////////////////////////////////////////
;//
;// init NASMX context stack
;//
;%push __NASMX_CTX__


;//////////////////////////////////////////////////////////////
;//
;// Set a Context Stack Value
;//
%macro NASMX_SET_CONTEXT_VALUE 2.nolist
	%xdefine %$$%1 %2
%endmacro


;//////////////////////////////////////////////////////////////
;//
;// native data sizes
;// Must be defined here due to struc_size!
%ixdefine byte_size    1
%ixdefine word_size    2
%ixdefine dword_size   4
%ixdefine qword_size   8
%ixdefine tword_size  10
%ixdefine oword_size  16
%ixdefine __m64_size   8
%ixdefine __m128_size 16
%ixdefine __m256_size 32
%ixdefine __int64_size   8
%ixdefine __int128_size 16
%ixdefine __nxfloat_size     4
%ixdefine __nxdouble_size    8
%ixdefine __nxfloat32_size   4
%ixdefine __nxfloat64_size   8
%ixdefine __nxfloat80_size  10
%ixdefine __nxfloat128_size 16
;// native register sizes
%idefine al_size  1
%idefine bl_size  1
%idefine cl_size  1
%idefine dl_size  1
%idefine ah_size  1
%idefine bh_size  1
%idefine ch_size  1
%idefine dh_size  1
%idefine ax_size  2
%idefine bx_size  2
%idefine cx_size  2
%idefine dx_size  2
%idefine di_size  2
%idefine si_size  2
%idefine sp_size  2
%idefine bp_size  2
%idefine bpl_size 1
%idefine dil_size 1
%idefine sil_size 1
%idefine spl_size 1
%idefine eax_size 4
%idefine ebx_size 4
%idefine ecx_size 4
%idefine edx_size 4
%idefine edi_size 4
%idefine esi_size 4
%idefine esp_size 4
%idefine ebp_size 4
%idefine rax_size 8
%idefine rbx_size 8
%idefine rcx_size 8
%idefine rdx_size 8
%idefine rdi_size 8
%idefine rsi_size 8
%idefine rsp_size 8
%idefine rbp_size 8
%idefine r8d_size  4
%idefine r9d_size  4
%idefine r10d_size 4
%idefine r11d_size 4
%idefine r12d_size 4
%idefine r13d_size 4
%idefine r14d_size 4
%idefine r15d_size 4
%idefine r8_size  8
%idefine r9_size  8
%idefine r10_size 8
%idefine r11_size 8
%idefine r12_size 8
%idefine r13_size 8
%idefine r14_size 8
%idefine r15_size 8

;// register aliases used to help with portability
%ifidn __BITS__,64
%ixdefine __AX rax
%ixdefine __BX rbx
%ixdefine __CX rcx
%ixdefine __DX rdx
%ixdefine __DI rdi
%ixdefine __SI rsi
%ixdefine __BP rbp
%ixdefine __SP rsp
%else
%ixdefine __AX eax
%ixdefine __BX ebx
%ixdefine __CX ecx
%ixdefine __DX edx
%ixdefine __DI edi
%ixdefine __SI esi
%ixdefine __BP ebp
%ixdefine __SP esp
%endif
;// register names used to help with macros invoke and uses
%ixdefine __nx_reg_eax eax
%ixdefine __nx_reg_ebx ebx
%ixdefine __nx_reg_ecx ecx
%ixdefine __nx_reg_edx edx
%ixdefine __nx_reg_edi edi
%ixdefine __nx_reg_esi esi
%ixdefine __nx_reg_ebp ebp
%ixdefine __nx_reg_esp esp
%ixdefine __nx_reg_rax rax
%ixdefine __nx_reg_rbx rbx
%ixdefine __nx_reg_rcx rcx
%ixdefine __nx_reg_rdx rdx
%ixdefine __nx_reg_rdi rdi
%ixdefine __nx_reg_rsi rsi
%ixdefine __nx_reg_rbp rbp
%ixdefine __nx_reg_rsp rsp
%ixdefine __nx_reg_r8  r8
%ixdefine __nx_reg_r9  r9
%ixdefine __nx_reg_r10 r10
%ixdefine __nx_reg_r11 r11
%ixdefine __nx_reg_r12 r12
%ixdefine __nx_reg_r13 r13
%ixdefine __nx_reg_r14 r14
%ixdefine __nx_reg_r15 r15


;//////////////////////////////////////////////////////////////
;//
;// nasm storage types
;//
%ixdefine byte__nx_reserve   RESB
%ixdefine word__nx_reserve   RESW
%ixdefine dword__nx_reserve  RESD
%ixdefine qword__nx_reserve  RESQ
%ixdefine tword__nx_reserve  REST
%ixdefine oword__nx_reserve  RESO
%ixdefine __m64__nx_reserve  RESQ
%ixdefine __m128__nx_reserve RESO
%ixdefine __int64__nx_reserve  RESQ
%ixdefine __int128__nx_reserve RESO
%ixdefine __nxfloat__nx_reserve    RESD
%ixdefine __nxdouble__nx_reserve   RESQ
%ixdefine __nxfloat32__nx_reserve  RESD
%ixdefine __nxfloat64__nx_reserve  RESQ
%ixdefine __nxfloat80__nx_reserve  RESO
%ixdefine __nxfloat128__nx_reserve RESO

;//////////////////////////////////////////////////////////////
;//
;// nasm storage types
;//
%ixdefine byte__nx_storage   DB
%ixdefine word__nx_storage   DW
%ixdefine dword__nx_storage  DD
%ixdefine qword__nx_storage  DQ
%ixdefine tword__nx_storage  DT
%ixdefine oword__nx_storage  DO
%ixdefine __m64__nx_storage  DQ
%ixdefine __m128__nx_storage DO
%ixdefine __int64__nx_storage  DQ
%ixdefine __int128__nx_storage DO
%ixdefine __nxfloat__nx_storage    DD
%ixdefine __nxdouble__nx_storage   DQ
%ixdefine __nxfloat32__nx_storage  DD
%ixdefine __nxfloat64__nx_storage  DQ
%ixdefine __nxfloat80__nx_storage  DO
%ixdefine __nxfloat128__nx_storage DO

;//////////////////////////////////////////////////////////////
;//
;// nasmx classifcation of types
;//
;// Bits used to contain classification:
;// for class/struc/union:
;//    0-3 : exponent of alignment (2**x)
;//   4-10 : reserved (0)
;// for integral types:
;//   0-10 : size of type in bytes
;// for all types:
;//     11 : reserved (0)
;//     12 : set if struct type
;//     13 : set if union type
;//     14 : set if class type
;//     15 : set if float type, otherwise clear
;//
%ixdefine byte__nx_type   0x0001
%ixdefine word__nx_type   0x0002
%ixdefine dword__nx_type  0x0004
%ixdefine qword__nx_type  0x0008
%ixdefine tword__nx_type  0x000A
%ixdefine oword__nx_type  0x0010
%ixdefine __m64__nx_type  0x8008
%ixdefine __m128__nx_type 0x8010
%ixdefine __m256__nx_type 0x8020
%ixdefine __int64__nx_type  0x8008
%ixdefine __int128__nx_type 0x8010
%ixdefine __nxfloat__nx_type    0x8004
%ixdefine __nxdouble__nx_type   0x8008
%ixdefine __nxfloat32__nx_type  0x8004
%ixdefine __nxfloat64__nx_type  0x8008
%ixdefine __nxfloat80__nx_type  0x800A
%ixdefine __nxfloat128__nx_type 0x8010

%xdefine __NX_STRUC_TYPE 0x1000
%xdefine __NX_UNION_TYPE 0x2000
%xdefine __NX_CLASS_TYPE 0x4000

;// NASMX int types
%ixdefine int8_t     byte
%ixdefine uint8_t    byte
%ixdefine int16_t    word
%ixdefine uint16_t   word
%ixdefine int32_t    dword
%ixdefine uint32_t   dword
%ixdefine long32_t   dword
%ixdefine ulong32_t  dword
%ixdefine int64_t    qword
%ixdefine uint64_t   qword
%ixdefine int80_t    tword
%ixdefine uint80_t   tword
%ixdefine int128_t   oword
%ixdefine uint128_t  oword
%ixdefine long64_t   qword
%ixdefine ulong64_t  qword
%ixdefine long128_t  oword
%ixdefine ulong128_t oword
;// NASMX Unicode Transformation Format types
%ixdefine utf8_t     uint8_t
%ixdefine utf16_t    uint16_t
%ixdefine utf32_t    uint32_t
;// C types
;// The classification of long_t type  must be performed
;// during __OUTPUT_FORMAT__ check as the actual sizes
;// are different among operating systems.
%ixdefine char_t     int8_t
%ixdefine uchar_t    uint8_t
%ixdefine short_t    int16_t
%ixdefine ushort_t   uint16_t
%ixdefine int_t      int32_t
%ixdefine uint_t     uint32_t
;// float types require special handling due to
;// nasm FLOAT directives!
%ixdefine float_t    __nxfloat
%ixdefine double_t   __nxdouble
%ixdefine float32_t  __nxfloat32
%ixdefine float64_t  __nxfloat64
%ixdefine float80_t  __nxfloat80
%ixdefine float128_t __nxfloat128
%idefine __float(v) dword __float32__(v)
%idefine __double(v) qword __float64__(v)

;// Map between native size and token.
;// The define name was chosen as it will
;// be displayed to the user if the macro
;// nx_token_from_size() is called with
;// an illegal value during assembly
%ixdefine __nx_error_token_size_1  byte
%ixdefine __nx_error_token_size_2  word
%ixdefine __nx_error_token_size_4  dword
%ixdefine __nx_error_token_size_8  qword
%ixdefine __nx_error_token_size_10 tword
%ixdefine __nx_error_token_size_16 xmm
%ixdefine __nx_error_token_size_32 xmm

%define typeof(x) ((x %+ __nx_type >> 12) & 0x000F)
%define sizeof(x) x %+ _size
%define reserve(x) x %+ __nx_reserve
%define declare(x) x %+ __nx_storage
%define nx_token_from_size(x) __nx_error_token_size_ %+ x
%idefine is_typeof_struc(x) ((x %+ __nx_type >> 12) & 0x0001)
%idefine is_typeof_union(x) ((x %+ __nx_type >> 13) & 0x0001)
%idefine is_typeof_class(x) ((x %+ __nx_type >> 14) & 0x0001)
%idefine is_typeof_float(x) ((x %+ __nx_type >> 15) & 0x0001)
%idefine nx_is_typeof_container(x) ((x %+ __nx_type >> 12) & 0x0007)

;// class and member access specifiers
%ixdefine __nx_class_const     0x0100
%ixdefine __nx_class_static    0x0200
%ixdefine __nx_class_abstract  0x0400
%ixdefine __nx_class_virtual   0x0800
%ixdefine __nx_class_private   0x1000
%ixdefine __nx_class_protected 0x2000
%ixdefine __nx_class_public    0x4000

;// class and member tests - returns 0 if false, otherwise non-zero
%idefine is_class_typeof_const(x) ((x %+ __nx_class_type) & __nx_class_const)
%idefine is_class_typeof_static(x) ((x %+ __nx_class_type) & __nx_class_static)
%idefine is_class_typeof_abstract(x) ((x %+ __nx_class_type) & __nx_class_abstract)
%idefine is_class_typeof_virtual(x) ((x %+ __nx_class_type) & __nx_class_virtual)
%idefine is_class_typeof_private(x) ((x %+ __nx_class_type) & __nx_class_private)
%idefine is_class_typeof_protected(x) ((x %+ __nx_class_type) & __nx_class_protected)
%idefine is_class_typeof_public(x) ((x %+ __nx_class_type) & __nx_class_public)

;//////////////////////////////////////////////////////////////
;//
;// NASMX ABI size and pointer types
;//
;//                 Windows     Linux       BSD
;//        type     32   64     32   64     32   64
;// sizeof(int)      4    4      4    4      4    4
;// sizeof(long)     4    4      4    8      4    8
;// sizeof(ptr)      4    8      4    8      4    8
;// sizeof(size_t)   4    8      4    8      4    8
%ixdefine size32_t dword
%ixdefine size64_t qword
%ixdefine size_t size%[__BITS__]_t
%assign __NASMX_ABI_BITS__ sizeof(size_t) * 8
%ifnidn __BITS__,__NASMX_ABI_BITS__
	%fatal unknown size_t: __BITS__
%endif
%ixdefine ptr32_t dword
%ixdefine ptr64_t qword
;// use for 32->64 bit expansion of either int or ptr
%ixdefine ptrdiff_t ptr%[__BITS__]_t
%ixdefine NASMX_PTR ptr%[__BITS__]_t
;// remember: intptr's can be confusing when going
;// from 32-bit to 64-bit as sizeof(ptr) is increased
;// to 8 but sizeof(int) remains 4 potential allowing
;// very large (long) ints when using intptrs as ints.
%ixdefine intptr_t ptrdiff_t
%ixdefine uintptr_t ptrdiff_t

;//////////////////////////////////////////////////////////////
;//
;// Calling Convention Enumerations
;// Used within IMPORT, PROTO, PROC, & INVOKE
;//
;// BIT
;//   0-3: PREFIX - index into decorations (i.e. '_', '@', or '?' )
;//        all bits clear if no prefix
;//   4-7: SUFFIX - index into decorations (i.e. '@', '?', '$' )
;//        all bits clear if no suffix
;//  8-11: CALLCONV - calling convention enum
;//    12: ARGROTATE - rotate direction of args pushed to stack
;//        set if left rotation ( PASCAL = %rotate 1 ), clear if right rotation ( CDECL = %rotate -1)
;//    13: RETPOPSARGS - stack adjustment responsibility
;//        set if callee pops args ( PASCAL/STDCALL ), clear if caller adjusts stack ( CDECL )
;//
;// Notes:
;//    You may create your own calling convention for your operating
;//    system of choice by modifying the flags and macros.  However,
;//    the standard calling conventions should continue to exist to
;//    permit interfacing with system calls ( unless you're writing
;//    an OS with a new ABI/API ;)
;//
%define __NASMX_DECLSPEC_CC_PREFIX_MASK__      0x0007
%define __NASMX_DECLSPEC_CC_SUFFIX_MASK__      0x0070
%define __NASMX_DECLSPEC_CC_ENUM_MASK__        0x0F00
%define __NASMX_DECLSPEC_CC_ARGROTATE_MASK__   0x1000
%define __NASMX_DECLSPEC_CC_RETPOPSARGS_MASK__ 0x2000

;// universal calling conventions
%idefine __NASMX_DECLSPEC_CALLCONV_NAKED__    0
%idefine __NASMX_DECLSPEC_CALLCONV_PASCAL__   0x3100
;// although currently specific to win32, the
;// STDCALL calling convention can be useful
%idefine __NASMX_DECLSPEC_CALLCONV_STDCALL__  0x2321
;// The following 3 calling conventions are highly
;// platform dependent and are defined within the
;// OUTPUT_FORMAT check
;// %idefine __NASMX_DECLSPEC_CALLCONV_CDECL__ 0x????
;// %idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x????
;// %idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x????

;// CALLCONV Enums
;// coincidentally compatible with DotGNU
;// System.Runtime.InteropServices.CallingConvention Enum
%idefine __NASMX_DECLSPEC_CC_ENUM_NAKED__     0
%idefine __NASMX_DECLSPEC_CC_ENUM_PASCAL__    1
%idefine __NASMX_DECLSPEC_CC_ENUM_CDECL__     2
%idefine __NASMX_DECLSPEC_CC_ENUM_STDCALL__   3
%idefine __NASMX_DECLSPEC_CC_ENUM_THISCALL__  4
%idefine __NASMX_DECLSPEC_CC_ENUM_FASTCALL__  5
;// %idefine __NASMX_DECLSPEC_CALLCONV_CC_ENUM_RDFCALL__   6

;// internal CALLCONV macros
%define nx_declspec_cc_prefix(x)       (x & 0x0007)
%define nx_declspec_cc_suffix(x)      ((x >> 4) & 0x0007)
%define nx_declspec_cc_enum(x)        ((x >> 8) & 0x000F)
%define nx_declspec_cc_argrotate(x)   ((x >> 12) & 0x0001)
%define nx_declspec_cc_retpopsargs(x) ((x >> 13) & 0x0001)

;// String containing chars that the prefix/suffix bits index into.
;// If you are adding __thiscall convention for your compiler of
;// choice make sure that the initial suffix char is present in
;// the decorations string.
%define __NASMX_DECLSPEC_CC_DECORATIONS__     '_@?$'
;// The following formatted string is used by the nx_is* functions
%define __NASMX_NUMALPHATOKEN__ '.+-0123456789EeABCDFabcdfGHIJKLMNOPQRSTUVWXYZghijklmnopqrstuvwxyz$@_'

;//////////////////////////////////////////////////////////////
;// internal macro calls
;// usage:
;//    __nx_stack_push STACKNAME, VALUE
;//    __nx_stack_pop STACKNAME
;//
%macro __nx_stack_push 2.nolist
	%ifdef __NX_STACK_IDX_%[%1]
		%assign %%idx __NX_STACK_IDX_%[%1]
		%assign %%idx ( %%idx + 1 )
		%ixdefine __NX_STACK_IDX_%[%1] %%idx
		%ixdefine __NX_STACK_%[%1]_%[%%idx] %2
	%else
		%ixdefine __NX_STACK_IDX_%[%1] 1
		%ixdefine __NX_STACK_%[%1]_1 %2
	%endif
%endmacro

%macro __nx_stack_pop 1.nolist
	%ifdef __NX_STACK_IDX_%[%1]
		%assign %%idx __NX_STACK_IDX_%[%1]
		%undef __NX_STACK_%[%1]_%[%%idx]
		%assign %%idx ( %%idx - 1 )
		%if ( %%idx != 0 )
			%xdefine __NX_STACK_IDX_%[%1] %%idx
		%else
			%undef __NX_STACK_IDX_%[%1]
		%endif
	%endif
%endmacro

;//////////////////////////////////////////////////////////////
;// internal macro call
;// used by IMPORT, PROC, & INVOKE
;// usage:
;//    nx_callconv_decorate callconv, funcname, suffix
;// examples:
;//    nx_callconv_decorate __NASMX_DECLSPEC_CALLCONV_STDCALL__, WinProc, 16
;//    nx_callconv_decorate __NASMX_DECLSPEC_CALLCONV_CDECL__, printf
;//    nx_callconv_decorate __NASMX_DECLSPEC_CALLCONV_THISCALL__, ClassName.MethodName, 'Z1yi4p8aue'
%macro nx_callconv_decorate 2-3.nolist 0
	%ifnum %1
		%assign %%__pidx nx_declspec_cc_prefix(%1)
		%assign %%__sidx nx_declspec_cc_suffix(%1)
	%else
		%fatal 'CALLCONV undefined:' %1
	%endif
	%ifnum %2
		%fatal 'internal error'
	%endif

	%if %%__pidx > 0
		%substr %%__sig __NASMX_DECLSPEC_CC_DECORATIONS__ %%__pidx
		%ifnum %2
			%fatal 'internal error'
		%elifid %2
			%defstr %%__func %2
		%eliftoken %2
			%defstr %%__func %2
		%else
			%define %%__func %2
		%endif
		%strcat %%__sig %%__sig,%%__func
	%else
		%ifstr %2
			%define %%__func %2
		%else
			%defstr %%__sig %2
		%endif
	%endif
	%if %%__sidx > 0
		%ifnum %3
			%defstr %%__suffix %3
		%elifid %3
			%defstr %%__suffix %3
		%else
			%ifstr %3
				%define %%__suffix %3
			%else
				%defstr %%__suffix %3
			%endif
		%endif
		%substr %%__stok __NASMX_DECLSPEC_CC_DECORATIONS__ %%__sidx
		%strcat %%__sig %%__sig,%%__stok,%%__suffix
	%endif

	%deftok %$__nxtok_decorated_name %%__sig

%endmacro

;//////////////////////////////////////////////////////////////
;//
;// Target Operating System Type definitions
;//
%define __NASMX_DECLSPEC_SYSTYPE_LINUX__   1
%define __NASMX_DECLSPEC_SYSTYPE_MACHOS__  2
%define __NASMX_DECLSPEC_SYSTYPE_BSD__     3
%define __NASMX_DECLSPEC_SYSTYPE_WINDOWS__ 4

;//////////////////////////////////////////////////////////////////
;// Macro to control NASMX default behavior
;// example usage:
;//    NASMX_PRAGMA PACK, PUSH, 2
;//    NASMX_PRAGMA PACK, POP
;//    NASMX_PRAGMA CALLSTACK, 32 ; Enable callstack optimization
;//    NASMX_PRAGMA CALLSTACK, 0  ; Disable callstack optimization
;//    NASMX_PRAGMA WARNING, DISABLE, ALL
;//    NASMX_PRAGMA WARNING, DISABLE, 8001[, 8002, 8003]
;//    NASMX_PRAGMA WARNING, ENABLE, ALL
;//    NASMX_PRAGMA INVOKE_FASTCALL_STACK_PRELOAD, ENABLE
;//    NASMX_PRAGMA PROC_FASTCALL_STACK_PRELOAD, DISABLE
;//    NASMX_PRAGMA INVOKE_FASTCALL_STACK_PRELOAD, ENABLE
;// The macro will eventually allow us to enable/disable
;// warnings generated by the NASMX macro type system
%imacro NASMX_PRAGMA 1-*.nolist
	%ifidni WARNING,%1
		%warning actual pragma warnings currently unimplemented
		%ifidni ENABLE, %2
			;// assert: warnings are enabled if undefined
			%ifidni ALL,%3
				%ifdef __NASMX_PRAGMA_WARNING_8001__
					%undef __NASMX_PRAGMA_WARNING_8001__
				%endif
				%ifdef __NASMX_PRAGMA_WARNING_8002__
					%undef __NASMX_PRAGMA_WARNING_8002__
				%endif
			%else
				%rep %0-2
					%rotate 1
					%ifdef __NASMX_PRAGMA_WARNING_%1__
						%undef __NASMX_PRAGMA_WARNING_%1__
					%endif
				%endrep
			%endif
		%elifidni DISABLE, %2
			;// assert: warnings are disabled if defined
			%ifidni ALL,%3
				%ifndef __NASMX_PRAGMA_WARNING_8001__
					%define __NASMX_PRAGMA_WARNING_8001__
				%endif
				%ifndef __NASMX_PRAGMA_WARNING_8002__
					%define __NASMX_PRAGMA_WARNING_8002__
				%endif
			%else
				%rep %0-2
					%rotate 1
					%ifndef __NASMX_PRAGMA_WARNING_%3__
						%define __NASMX_PRAGMA_WARNING_%3__
					%endif
				%endrep
			%endif
		%else
			%error 'syntax: nasmx_pragma warning, [enable | disable], ...'
		%endif
	%elifidni CALLSTACK, %1
		;// This option is very useful with fastcall
		%ifdef NASMX_ENDPROC
			%error %1 pragma cannot be defined within procedure definition
		%endif
		%ifnum %2
			%assign %%__nx_stack_adjust %2
			%if %%__nx_stack_adjust > 0
				;// assert: turning on call stack feature
				%ifidni __OUTPUT_FORMAT__, win64
					;// assert: Win64 calling convention requires
					;// that the call stack be at least 32
					%if %%__nx_stack_adjust < 32
						%assign %%__nx_stack_adjust 32
					%endif
				%endif
				;// Note: x64 calling convention requires that
				;// the call stack be aligned to 16 bytes.
				;// Use 8 bytes for x86
				%assign %%__nx_align __NASMX_ABI_BITS__ / 4
				%assign %%__off (((%%__nx_stack_adjust + %%__nx_align) / %%__nx_align) * %%__nx_align)
				%assign %%__tmp (%%__nx_stack_adjust + %%__nx_align)
				%if (%%__off != %%__tmp)
					%assign %%__nx_stack_adjust %%__off
				%endif
			%endif
			;// This must be a global define since it is used within the procedure
			;// and during invoke and thus could be hidden by one or more user contexts
			%ifdef __NX_PROLOGUE_CALLSTACK_ADJUST__
				%undef __NX_PROLOGUE_CALLSTACK_ADJUST__
			%endif
			%if %%__nx_stack_adjust > 0
				%xdefine __NX_PROLOGUE_CALLSTACK_ADJUST__ %%__nx_stack_adjust
			%endif
		%else
			%error %1 pragma requires valid byte count
		%endif
	%elifidni FASTCALL_STACK_PRELOAD, %1
		;// NASMX 1.4 - The behavior of this pragma was changed
		;// to account for new proc/invoke fastcall preloading behavior.
		;// Beginning with this version of NASMX invoke fastcall stack preload
		;// is disabled by default.
		%warning 'This pragma option is deprecated.'
		%ifidni ENABLE, %2
			%ifndef ENABLE_INVOKE_FASTCALL_STACK_PRELOAD
				%xdefine ENABLE_INVOKE_FASTCALL_STACK_PRELOAD 1
			%endif
		%elifidni DISABLE, %2
			%ifdef ENABLE_INVOKE_FASTCALL_STACK_PRELOAD
				%undef ENABLE_INVOKE_FASTCALL_STACK_PRELOAD
			%endif
		%else
			%error 'This pragma option is deprecated.'
		%endif
	%elifidni INVOKE_FASTCALL_STACK_PRELOAD, %1
		;// by default, invoke fastcall stack preload is disabled
		%ifidni ENABLE, %2
			%ifndef ENABLE_INVOKE_FASTCALL_STACK_PRELOAD
				%xdefine ENABLE_INVOKE_FASTCALL_STACK_PRELOAD 1
			%endif
		%elifidni DISABLE, %2
			%ifdef ENABLE_INVOKE_FASTCALL_STACK_PRELOAD
				%undef ENABLE_INVOKE_FASTCALL_STACK_PRELOAD
			%endif
		%else
			%error 'syntax: nasmx_pragma invoke_fastcall_stack_preload, [enable | disable]'
		%endif
	%elifidni PROC_FASTCALL_STACK_PRELOAD, %1
		;// by default, proc fastcall stack preload is enabled
		%ifidni DISABLE, %2
			%ifndef DISABLE_PROC_FASTCALL_STACK_PRELOAD
				%xdefine DISABLE_PROC_FASTCALL_STACK_PRELOAD 1
			%endif
		%elifidni ENABLE, %2
			%ifdef DISABLE_PROC_FASTCALL_STACK_PRELOAD
				%undef DISABLE_PROC_FASTCALL_STACK_PRELOAD
			%endif
		%else
			%error 'syntax: nasmx_pragma proc_fastcall_stack_preload, [enable | disable]'
		%endif
	%elifidni PACK, %1
		%ifidni PUSH, %2
			%assign %%maxsize ( __BITS__ / 2 )
			%if ( %0 < 3 )
				%fatal missing packing alignment value
			%elif ( %3 > %%maxsize )
				%error cannot align larger than %%maxsize
			%elif ( %3 > 1 )
				%assign %%exp 0
				%assign %%align %3
				%rep %3
					%if ((%%align & 0x0001) == 0 )
						%assign %%exp ( %%exp + 1 )
						%assign %%align ( %%align >> 1 )
					%else
						%exitrep
					%endif
				%endrep
				%if ( %%align != 1 )
					%fatal alignment must be a small power of 2
				%endif
			%endif
			
			__nx_stack_push pack, %3
		%elifidni POP, %2
			__nx_stack_pop pack
		%else
			%error unknown packing directive
		%endif
	%else
		%error 'unknown nasmx_pragma:' %1
	%endif
%endmacro

;//////////////////////////////////////////////////////////////////
;// Macro to override default ABI behavior (Declare Specialization)
;// example usage:
;//    NASMX_DECLSPEC CALLCONV, PASCAL
;//    NASMX_DECLSPEC CALLCONV, STDCALL, DEFAULT
;//    NASMX_DECLSPEC SYSTYPE, LINUX
;//
;// notes:
;//    Make sure you understand the effects of using this command
;//    before making a global declaration!  Unresolved linker errors
;//    may haunt you!
%imacro NASMX_DECLSPEC 1-8.nolist
	%ifidni %1,CALLCONV
		%if %0 < 2
			%error 'nasmx_declspec syntax'
		%endif
		%ifndef __NASMX_DECLSPEC_CALLCONV_%[%2]__
			%error 'unknown declspec calltype:' %2
		%endif
		%if %0 == 2
			%ixdefine __NASMX_DECLSPEC_CALLCONV_DEFAULT__ __NASMX_DECLSPEC_CALLCONV_%[%2]__
		%else
			%ifdef __NASMX_DECLSPEC_CALLCONV_%[%3]__
				%warning 'declspec redefining' %1 %2 %3
			%endif
			%ixdefine __NASMX_DECLSPEC_CALLCONV_%[%3]__ __NASMX_DECLSPEC_CALLCONV_%[%2]__
		%endif
	%else
		%ifidni %1,SYSTYPE
			%ifndef __NASMX_DECLSPEC_SYSTYPE_%[%2]__
				%error 'unknown declspec systype:' %2
			%endif
			%if %0 == 2
				%ixdefine __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ __NASMX_DECLSPEC_SYSTYPE_%[%2]__
			%else
				%ifdef __NASMX_DECLSPEC_SYSTYPE_%[%3]__
					%warning 'declspec redefining' %1 %2 %3
				%endif
				%ixdefine __NASMX_DECLSPEC_SYSTYPE_%[%3]__ __NASMX_DECLSPEC_SYSTYPE_%[%2]__
			%endif
		%else
			%error 'unknown declspec:' %1
		%endif
	%endif
%endmacro


;//////////////////////////////////////////////////////////////////
;// OUTPUT_FORMAT check
;//
;// All system specific defines are made here
;//
%ifidn	 __OUTPUT_FORMAT__,elf
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0200
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x0410
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x0500
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    2
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  0
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_4__ 'ECXEDX'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_2__ 'CX DX '
	%ifdef FREEBSD
		NASMX_DECLSPEC SYSTYPE, BSD
	%elifdef NETBSD
		NASMX_DECLSPEC SYSTYPE, BSD
	%elifdef OPENBSD
		NASMX_DECLSPEC SYSTYPE, BSD
	%else
		NASMX_DECLSPEC SYSTYPE, LINUX
	%endif
	NASMX_DECLSPEC CALLCONV, CDECL, DEFAULT
	%idefine long_t long32_t
	%idefine ulong_t ulong32_t
	%idefine wchar_t dword
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf32__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%elifidn __OUTPUT_FORMAT__,elf32
	;// gcc does NOT prepend underscores to functions
	;// declared using cdecl
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0200
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x0410
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x0500
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    2
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  0
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_4__ 'ECXEDX'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_2__ 'CX DX '
	%ifdef FREEBSD
		NASMX_DECLSPEC SYSTYPE, BSD	
	%elifdef NETBSD
		NASMX_DECLSPEC SYSTYPE, BSD	
	%elifdef OPENBSD
		NASMX_DECLSPEC SYSTYPE, BSD	
	%else
		NASMX_DECLSPEC SYSTYPE, LINUX
	%endif
	NASMX_DECLSPEC CALLCONV, CDECL, DEFAULT
	%idefine long_t long32_t
	%idefine ulong_t ulong32_t
	%idefine wchar_t dword
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf32__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%elifidn __OUTPUT_FORMAT__,elf64
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0200
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x0410
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x0500
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    6
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  8
	%define __NASMX_DECLSPEC_FASTCALL_REGFLOATARGS_8__ 'XMM0XMM1XMM2XMM3XMM4XMM5XMM6XMM7'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_8__ 'RDIRSIRDXRCXR8 R9 '
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_4__ 'EDIESIEDXECXR8DR9D'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_2__ 'DI SI DX CX R8WR9W'
	%ifdef FREEBSD
		NASMX_DECLSPEC SYSTYPE, BSD	
	%elifdef NETBSD
		NASMX_DECLSPEC SYSTYPE, BSD	
	%elifdef OPENBSD
		NASMX_DECLSPEC SYSTYPE, BSD	
	%else
		NASMX_DECLSPEC SYSTYPE, LINUX
	%endif
	NASMX_DECLSPEC CALLCONV, FASTCALL, DEFAULT
	%idefine long_t long64_t
	%idefine ulong_t ulong64_t
	%idefine wchar_t dword
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf32__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%elifidn __OUTPUT_FORMAT__,macho
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0201
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x0411
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x0501
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    0
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  0
	NASMX_DECLSPEC SYSTYPE, MACHOS
	NASMX_DECLSPEC CALLCONV, CDECL, DEFAULT
	%idefine long_t long32_t
	%idefine ulong_t ulong32_t
	%idefine wchar_t dword
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf32__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%elifidn __OUTPUT_FORMAT__,macho32
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0201
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x0411
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x0501
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    0
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  0
	NASMX_DECLSPEC SYSTYPE, MACHOS
	NASMX_DECLSPEC CALLCONV, CDECL, DEFAULT
	%idefine long_t long32_t
	%idefine ulong_t ulong32_t
	%idefine wchar_t dword
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf32__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%elifidn __OUTPUT_FORMAT__,macho64
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0201
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x0411
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x0501
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    6
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  8
	%define __NASMX_DECLSPEC_FASTCALL_REGFLOATARGS_8__ 'XMM0XMM1XMM2XMM3XMM4XMM5XMM6XMM7'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_8__ 'RDIRSIRDXRCXR8 R9 '
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_4__ 'EDIESIEDXECXR8dR9d'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_2__ 'DI SI DX CX R8wR9w'
	NASMX_DECLSPEC SYSTYPE, MACHOS
	NASMX_DECLSPEC CALLCONV, FASTCALL, DEFAULT
	%idefine long_t long64_t
	%idefine ulong_t ulong64_t
	%idefine wchar_t dword
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf32__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%elifidn __OUTPUT_FORMAT__,win32
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0201
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x2423
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x2522
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    2
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  0
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_4__ 'ECXEDX'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_2__ 'CX DX '
	NASMX_DECLSPEC SYSTYPE, WINDOWS
	NASMX_DECLSPEC CALLCONV, STDCALL, DEFAULT
	%idefine long_t long32_t
	%idefine ulong_t ulong32_t
	%idefine wchar_t word
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf16__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%elifidn __OUTPUT_FORMAT__,win64
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0201
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x2423
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x0500
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    4
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  4
	%define __NASMX_DECLSPEC_FASTCALL_REGFLOATARGS_8__ 'XMM0XMM1XMM2XMM3'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_8__ 'RCXRDXR8 R9 '
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_4__ 'ECXEDXR8DR9D'
	%define __NASMX_DECLSPEC_FASTCALL_REGINTARGS_2__ 'CX DX R8WR9W'
	NASMX_DECLSPEC SYSTYPE, WINDOWS
	NASMX_DECLSPEC CALLCONV, FASTCALL, DEFAULT
	%idefine long_t long32_t
	%idefine ulong_t ulong32_t
	%idefine wchar_t word
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf16__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%else
	%idefine __NASMX_DECLSPEC_CALLCONV_CDECL__    0x0200
	%idefine __NASMX_DECLSPEC_CALLCONV_THISCALL__ 0x0410
	%idefine __NASMX_DECLSPEC_CALLCONV_FASTCALL__ 0x0500
	%define __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__    0
	%define __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__  0
	NASMX_DECLSPEC SYSTYPE, LINUX
	NASMX_DECLSPEC CALLCONV, CDECL, DEFAULT
	%if sizeof(size_t) == 32
		%idefine long_t long32_t
		%idefine ulong_t ulong32_t
	%else
		%idefine long_t long64_t
		%idefine ulong_t ulong64_t
	%endif
	%idefine wchar_t dword
	%ifdef UNICODE
		%idefine NASMX_TCHAR wchar_t
		%idefine NASMX_TEXT(x) __utf32__(x)
	%else
		%idefine NASMX_TCHAR char_t
		%idefine NASMX_TEXT(x) x
	%endif
%endif

;// pull in appropriate syscalls
%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_BSD__
    %ifdef FREEBSD
	%include 'nasmx/bsd/syscalls.freebsd.inc'
    %elifdef NETBSD
	%include 'nasmx/bsd/syscalls.netbsd.inc'
    %elifdef OPENBSD
	%include 'nasmx/bsd/syscalls.openbsd.inc'
    %endif
%elif __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_LINUX__
    %include 'nasmx/linux/syscall.inc'
%endif


;//////////////////////////////////////////////////////////////
;// This internal macro creates the class/struc or union
;// member offsets.  It expects the final member count to
;// be passed as a parameter.  It must only be called when
;// there is no parent container during nasmx_endproc.
;// This macro is required due to the fact we can't know, at
;// time of definition, what the alignment of the union must
;// be until AFTER all union members have been processed.
;// Subsequently, we can't perform offset equate processing
;// from within nasmx_reserve.  See: winsock.inc SOCKADDR_IN
%macro __nx_finalize_equates 1.nolist
%push __NX_CTX_FINALIZE
	%assign %%__max_align ( __BITS__ / 4 )
	%assign %$__nx_usize 0
	%assign %$__nx_offset 0
	%assign %%__idx 1
	%rep %1
		;// obtain the name for equating, checking for sentinal
		%xdefine %%__name %[__NX_EQUATE_NAME_%+ %%__idx]

		%ifidn %%__name, __NX_CTX_POP
			;// Get the size of the current container
			%assign %%__size %$__nx_usize

			; %ifdef __NX_DEBUG_STRUC
			;	%warning popping context, container size: %%__size
			; %endif

			%pop
			%ifnctx __NX_CTX_UNION
				%assign %$__nx_offset ( %$__nx_offset + %%__size )
			%endif
		%else
			;// obtain the type and size of the equate to build
			%xdefine %%__type %[%%__name %+ __nx_type]
			%assign %%__size %[%%__name %+ _size]

			;// In order to properly align the offset we need
			;// to determine if we're pointing at a container
			;// or one of it's members.
			%assign %%__is_container nx_is_typeof_container(%%__name)
			%if ( %%__is_container != 0 )
				;// struc/union alignment has conveniently
				;// already been established, thus we simply
				;// simply obtain that value.
				;// %assign %%__align %[%%__name %+ _align]
				%assign %%__align (0x0001 << (%%__type & 0x000F))

				;// each child container gets it's own ctx and
				;// offset in order to prevent nested strucs that
				;// are contained within the parent union from
				;// modifying other union members offsets.
				%assign %%__ofst %$__nx_offset
 				%if ( is_typeof_union(%%__name) != 0 )
					; %ifdef __NX_DEBUG_STRUC
					;	%warning pushing union %%__name
					; %endif
 					%push __NX_CTX_UNION
				%else
					;// assert: struc/class
					; %ifdef __NX_DEBUG_STRUC
					;	%warning pushing struct %%__name
					; %endif
 					%push __NX_CTX_STRUC
 				%endif
				%assign %$__nx_usize %%__size
				%assign %$__nx_offset %%__ofst
			%else
				;// Obtain the alignment requirement
				;// from the base type of this member.
				%assign %%__align ( %%__type & 0x00FF )
			%endif

			;// If the alignment requirement for the current 
			;// member being defined is greater than the max
			;// alignment size then clamp to max.
			%ifdef __NX_STACK_IDX_PACK
				%assign %%idx __NX_STACK_IDX_PACK
				%assign %%__pack __NX_STACK_PACK_%[%%idx]
				;// if the alignment of the member exceeds the
				;// packing alignment then use packing.
				%if ( %%__align > %%__pack )
					%assign %%__align %%__pack
				%endif
			%elif ( %%__align > %%__max_align )
				%assign %%__align %%__max_align
			%endif

			%if ( %%__align > 1 )
				%assign %%__off (((%$__nx_offset + %%__align) / %%__align) * %%__align)
				%assign %%__tmp (%$__nx_offset + %%__align)
				%if ( %%__off != %%__tmp )
					%assign %$__nx_offset %%__off
				%endif
			%endif

			;// Do not equate the outermost parent!
			%if ( %%__idx > 1 )
				%[%%__name] equ %$__nx_offset
				; %ifdef __NX_DEBUG_STRUC
				;	%assign %%toff %[%%__name]
				;	%warning name: %%__name type: %%__type size: %%__size align: %%__align off: %%toff
				; %endif

				%if ( %%__is_container == 0 )
					%ifnctx __NX_CTX_UNION
						%assign %$__nx_offset %$__nx_offset + %%__size
					%endif
				%endif
			%endif

		%endif  ;// if __NX_CTX_POP

		%assign %%__idx ( 1 + %%__idx )

	%endrep

	%ifctx __NX_CTX_FINALIZE
		; %ifdef __NX_DEBUG_STRUC
		;	%assign %%tsize %$__nx_offset
		;	%warning ctx ok, final offset: %%tsize , undefining equated names
		; %endif
		%assign %%__idx 1
		%rep %1
			%undef __NX_EQUATE_NAME_%[%%__idx]
			%assign %%__idx ( %%__idx + 1 )
		%endrep
		%pop
	%else
		%fatal internal ctx error
	%endif
%endmacro

;//////////////////////////////////////////////////////////////
;//
;// NASMX_STRUC
;//
%imacro NASMX_STRUC 1-3.nolist __NX_ROOT, __NX_CTX_STRUC
	%ifnidni %3,__NX_CTX_STRUC
		%ifnidni %3,__NX_CTX_UNION
			%ifnidni %3,__NX_CTX_CLASS
				%fatal unknown arg: %{3}
			%endif
		%endif
	%endif

	;// NASMX 1.3 - all strucs/unions must be named in order
	;// to ensure proper member alignment and offset equates
	;// regardless of nesting depth
	%ifidni %1, __NX_ROOT
		%fatal struc or union requires name
	%endif

	%ifctx __NX_CTX_STRUC
		%define %%__is_nested 1
		%assign %%__equcount %$__nx_equcount
	%elifctx __NX_CTX_UNION
		%define %%__is_nested 1
		%assign %%__equcount %$__nx_equcount
	%elifctx __NX_CTX_CLASS
		%define %%__is_nested 1
		%assign %%__equcount %$__nx_equcount
	%else
		%define %%__is_nested 0
		%assign %%__equcount 0
	%endif
	

	%if ( %%__is_nested == 0 )
		%xdefine %%__tname %1
	%else
		%xdefine %%__tname %{$__nx_name}.%1
	%endif
	%assign %%__equcount ( %%__equcount + 1 )
	%xdefine __NX_EQUATE_NAME_%[%%__equcount] %%__tname

	;// create new ctx and initialize
	%push %3
	%xdefine %$__nx_name %%__tname
	%define %$__nx_isnested %%__is_nested
		
	;// __nx_align contains the largest base type defined by a struc member
	;// and is used to calculate final union/struc size.
	%assign %$__nx_align 1

	;// __nx_usize contains the number of bytes for the current union/struc.
	%assign %$__nx_usize 0
	%assign %$__nx_offset 0
	%assign %$__nx_equcount %%__equcount

	%xdefine %{$__nx_name}__nx_reserve byte__nx_reserve
	%xdefine %{$__nx_name}__nx_storage byte__nx_storage
%endmacro

%imacro NASMX_UNION 1-2.nolist __NX_ROOT
	NASMX_STRUC %1, %2, __NX_CTX_UNION
%endmacro

%imacro NASMX_CLASS 1-2.nolist __NX_ROOT
	NASMX_STRUC %1, %2, __NX_CTX_CLASS
%endmacro

%imacro NASMX_ALIGN 1.nolist
	%ifnctx __NX_CTX_STRUC
		%ifnctx __NX_CTX_UNION
			%fatal corrupt context
		%endif
	%endif
	%if (%1 > 0)
		%assign %%__off (((%$__nx_size + %1) / %1) * %1)
		%assign %%__tmp (%$__nx_size + %1)
		%if (%%__off != %%__tmp)
			%assign %$__nx_size %%__off
		%endif
	%endif
%endmacro

;// usage:
;//   NASMX_RESERVE hWnd, NASMX_PTR, 1
%imacro NASMX_RESERVE 2-3.nolist 1
	%ifnctx __NX_CTX_STRUC
		%ifnctx __NX_CTX_UNION
			%ifnctx __NX_CTX_CLASS
				%fatal corrupt context
			%endif
		%endif
	%endif
	%iftoken %{2}_size
		%assign %%__argsize %{2}_size
		%if (%%__argsize < 1)
			%fatal invalid size for %{$__nx_name}.%{1}: %{2}
		%endif
	%else
		%fatal unknown size for %{$__nx_name}.%{1}: %{2}
	%endif

	%ifndef %{2}__nx_type
		%fatal unknown type tag for %{$__nx_name}.%{1}
	%endif

	%ifndef %{2}__nx_storage
		%fatal unknown storage tag for %{$__nx_name}.%{1}
	%endif

	%assign %%__qty %{3}
	%if (%%__qty < 1)
		%fatal invalid arg qty  for %{$__nx_name}.%{1}: %{3}
	%endif

	%if ( nx_is_typeof_container(%[%{2}]) != 0 )
		;// support array of strucs
		%assign %%size sizeof(%{2})
		%assign %%__amt (%%size * %%__qty)
		%xdefine %[%{$__nx_name}.%{1}]_size %%__amt
		;// use struc alignment as type
		%assign %%typ %[%{2}__nx_type]
		%assign %%__align (0x0001 << (%%typ & 0x000F))
		%xdefine %[%{$__nx_name}.%{1}]__nx_type %%__align
		%xdefine %[%{$__nx_name}.%{1}]__nx_reserve byte__nx_reserve
		%xdefine %[%{$__nx_name}.%{1}]__nx_storage byte__nx_storage
	%else
		%assign %%__amt (%%__argsize * %%__qty)
		%xdefine %[%{$__nx_name}.%{1}]_size %%__amt
		%xdefine %[%{$__nx_name}.%{1}]__nx_type %[%{2}]__nx_type
		%xdefine %[%{$__nx_name}.%{1}]__nx_reserve %[%{2}]__nx_reserve
		%xdefine %[%{$__nx_name}.%{1}]__nx_storage %[%{2}]__nx_storage
	%endif

	;// create the equate names for offset processing
	%assign %$__nx_equcount ( %$__nx_equcount + 1 )
	%xdefine __NX_EQUATE_NAME_%[%$__nx_equcount] %[%{$__nx_name}.%{1}]

	%assign %%__is_container nx_is_typeof_container(%{2})
	%if ( %%__is_container != 0 )
		;// struc/union alignment has conveniently
		;// already been established, thus we simply
		;// simply obtain that value.  Remember,
		;// container alignment is in exponent form!
		%assign %%typ %[%{2}__nx_type]
		%assign %%__align (0x0001 << (%%typ & 0x000F))
	%else
		;// if the size of the base type for the current
		;// member being defined is greater than the max
		;// alignment size then clamp to max.
		%assign %%__align __NASMX_ABI_BITS__ / 4
		%if ( %%__argsize > %%__align )
			%assign %%__argsize %%__align
		%endif
		%assign %%__align %%__argsize
	%endif

	%ifdef __NX_STACK_IDX_PACK
		%assign %%idx __NX_STACK_IDX_PACK
		%assign %%__pack __NX_STACK_PACK_%[%%idx]
		;// if the alignment of the member exceeds the
		;// packing alignment then use packing.
		%if ( %%__align > %%__pack )
			%assign %%__align %%__pack
		%endif
	%endif

	;// if the alignment requirement for this member is the
	;// largest observed thus far then save it for later.
	%if ( %%__align > %$__nx_align )
		%assign %$__nx_align %%__align
	%endif

	%ifctx __NX_CTX_UNION
		;// update current union size
		%if (%%__amt > %$__nx_usize)
			%assign %$__nx_usize %%__amt
		%endif
	%else
		;// ensure struct/class member offset naturally alignment
		%if ( %%__align > 1 )
			%assign %%__off (((%$__nx_offset + %%__align) / %%__align) * %%__align)
			%assign %%__tmp (%$__nx_offset + %%__align)
			%if ( %%__off != %%__tmp )
				%assign %$__nx_usize (%$__nx_usize + %%__off - %$__nx_offset)
				%assign %$__nx_offset %%__off
			%endif
		%endif

		;// update running size and offset
		%assign %$__nx_usize (%$__nx_usize + %%__amt)
		%assign %$__nx_offset (%$__nx_offset + %%__amt)
	%endif

%endmacro

%imacro NASMX_ENDSTRUC 0.nolist
	%ifnctx __NX_CTX_STRUC
		%ifnctx __NX_CTX_UNION
			%ifnctx __NX_CTX_CLASS
				%fatal corrupt context
			%endif
		%endif
	%endif

	;// adjust size of container using largest alignment value observed
	%if ( %$__nx_align > 1 )
		%assign %%__align %$__nx_align
		%assign %%__off (((%$__nx_usize + %%__align) / %%__align) * %%__align)
		%assign %%__tmp (%$__nx_usize + %%__align)
		%if (%%__off != %%__tmp)
			%assign %$__nx_usize (%$__nx_usize + %%__off - %$__nx_usize)
		%endif
	%endif

	;// Create the container size tag
	%[%{$__nx_name}]_size EQU %$__nx_usize

	;// Create the container type tag
	%assign %%exp 0
	%assign %%align %$__nx_align
	%assign %%count %%align
	%rep %%count
		%if ((%%align & 0x0001) == 0 )
			%assign %%exp ( %%exp + 1 )
			%assign %%align ( %%align >> 1 )
		%else
			%exitrep
		%endif
	%endrep
	%ifctx __NX_CTX_STRUC
		%assign %%type __NX_STRUC_TYPE
	%elifctx __NX_CTX_UNION
		%assign %%type __NX_UNION_TYPE
	%else
		%assign %%type __NX_CLASS_TYPE
	%endif
	%assign %%type (%%type | %%exp)

	%xdefine %[%{$__nx_name}]__nx_type %%type
	
	;// save ctx data and pop stack
	%xdefine %%__tname %$__nx_name 
	%assign %%__align %$__nx_align
	%assign %%__usize %$__nx_usize
	%assign %%__equcount ( %$__nx_equcount + 1 )
	%pop

	%xdefine __NX_EQUATE_NAME_%[%%__equcount] __NX_CTX_POP

	%ifctx __NX_CTX_UNION
		%assign %%__was_nested 1
	%elifctx __NX_CTX_STRUC
		%assign %%__was_nested 1
	%elifctx __NX_CTX_CLASS
		%assign %%__was_nested 1
	%else
		%assign %%__was_nested 0
	%endif

	%if ( %%__was_nested != 0 )
		%assign %$__nx_equcount %%__equcount
		;// adjust the current container size and offset since we
		;// now know the alignment requirement of the sub-container.
		%if ( %%__align > %$__nx_align )
			%assign %$__nx_align %%__align
		%endif
		%ifctx __NX_CTX_UNION
			%if ( %%__usize > %$__nx_usize )
				%assign %$__nx_usize %%__usize
			%endif
		%else
			%if ( %%__align > 1 )
				%assign %%__off (((%$__nx_offset + %%__align) / %%__align) * %%__align)
				%assign %%__tmp (%$__nx_offset + %%__align)
				%if ( %%__off != %%__tmp )
					%assign %$__nx_usize (%$__nx_usize + %%__off - %$__nx_offset)
					%assign %$__nx_offset %%__off
				%endif
			%endif
			%assign %$__nx_usize ( %$__nx_usize + %%__usize )
			%assign %$__nx_offset ( %$__nx_offset + %%__usize )
		%endif
	%else
		;// Create all container and member equates.
		__nx_finalize_equates %%__equcount
	%endif
	
%endmacro

%idefine NASMX_ENDUNION NASMX_ENDSTRUC
%idefine NASMX_ENDCLASS NASMX_ENDSTRUC

%imacro NASMX_ISTRUC 0-*.nolist __NX_ROOT, __NX_ROOT, __NX_CTX_ISTRUC
	%ifnidni %{3},__NX_CTX_ISTRUC
		%ifnidni %{3},__NX_CTX_IUNION
			%ifnidni %{3},__NX_CTX_ICLASS
				%fatal unknown arg: %{3}
			%endif
		%endif
	%endif
	%ifctx __NX_CTX_ISTRUC
		%define %%__is_nested 1
	%elifctx __NX_CTX_IUNION
		%define %%__is_nested 1
	%else
		%define %%__is_nested 0
	%endif
	%ifnidni %{1},__NX_ROOT
		%define %%__is_named 1
	%else
		%define %%__is_named 0
	%endif
	%if (%%__is_nested == 0)
		%if (%%__is_named == 0)
			%fatal root structure or union requires name
		%endif
		%ifidni %2, __NX_ROOT
			%fatal root structure or union requires base type
		%endif
		%push %3
		%xdefine %$__nx_istrucstart %{1}
		%xdefine %$__nx_name %{2}
		%[%$__nx_istrucstart]:
	%else
		%if (%%__is_named == 0)
			%xdefine %%__tname %{$__nx_name}
		%else
			%xdefine %%__tname %{$__nx_name}.%{1}
			%assign %%__off %%__tname
			%assign %%__times %%__off-($-%[%$__nx_istrucstart])
			%if (%%__times > 0)
				times %%__times db 0
			%endif
		%endif
		%push  %3
		%xdefine %$__nx_istrucstart %[%$$__nx_istrucstart]
		%xdefine %$__nx_name %%__tname
	%endif
	%define %$__nx_isnamed %%__is_named
%endmacro

%idefine NASMX_IUNION NASMX_ISTRUC

%imacro NASMX_AT 1-2+.nolist
	%assign %%__ofs %{$__nx_name}.%{1}
	%assign %%__count %%__ofs-($-%$__nx_istrucstart)
	%if (%%__count > 0)
		times %%__count db 0
	%endif
	%{$__nx_name}.%{1}__nx_storage %2
%endmacro

%imacro NASMX_IENDSTRUC 0.nolist
	;// assert: finish up struc if needed
	%if (%$__nx_isnamed == 1)
		%assign %%__times %{$__nx_name}_size-($-%$__nx_istrucstart)
		%if (%%__times > 0)
			times %%__times db 0
		%endif
	%endif
	%pop
%endmacro

%idefine NASMX_IENDUNION NASMX_IENDSTRUC


;//////////////////////////////////////////////////////////////
;// MACRO nx_isalnum
;//
;// Purpose
;//    This macro is designed to return in the current context
;//    stack variable %$__nx_isalnum_bool if the parameter is
;//    alphanumeric.
;//
;// Usage:
;//    nx_isalnum chr
;//    nx_isalnum 'x'
;//
%macro nx_isalnum 1.nolist
    %ifstr %1
        %define %%__arg_chr %1
    %else
        %defstr %%__arg_chr %1
    %endif
    %assign %%__count 62
    %assign %%__idx 3
    %assign %$__nx_isalnum_bool 0
    %rep %%__count
        %assign %%__idx %%__idx + 1
        %substr %%__chr __NASMX_NUMALPHATOKEN__ %%__idx, 1
        %ifidn %%__chr, %%__arg_chr
            %assign %$__nx_isalnum_bool %%__idx
            %exitrep
        %endif
    %endrep
%endmacro

;//////////////////////////////////////////////////////////////
;// MACRO nx_ishexchr
;//
;// Purpose
;//    This macro is designed to return in the current context
;//    stack variable %$__nx_ishexnum_bool if the parameter is
;//    hexadecimal.
;//
;// Usage:
;//    nx_ishexchr chr
;//    nx_ishexchr 'f'
;//
%macro nx_ishexchr 1.nolist
    %ifstr %1
        %define %%__arg_chr %1
    %else
        %defstr %%__arg_chr %1
    %endif
    %assign %%__count 22
    %assign %%__idx 3
    %assign %$__nx_ishexchr_bool 0
    %rep %%__count
        %assign %%__idx %%__idx + 1
        %substr %%__chr __NASMX_NUMALPHATOKEN__ %%__idx, 1
        %ifidn %%__chr, %%__arg_chr
            %assign %$__nx_ishexchr_bool %%__idx
            %exitrep
        %endif
    %endrep
%endmacro

;//////////////////////////////////////////////////////////////
;// MACRO nx_isfloattok
;//
;// Purpose
;//    This macro is designed to return in the current context
;//    stack variable %$__nx_isfloattok_bool if the parameter is
;//    a float token and %$__nx_isfloattok_num returns the number.
;//
;// Usage:
;//    %define PI 3.14159
;//    nx_isfloattok PI
;//    nx_isfloattok __float(2.0)
;//    nx_isfloattok string
;//
%macro nx_isfloattok 1-2.nolist 0
    %assign %$__nx_isfloattok_num 0
    %ifnum %1
        %assign %$__nx_isfloattok_bool 0
    %else
        %ifstr %1
            %define %%__arg_str %1
        %else
            %defstr %%__arg_str %1
        %endif
        nx_strstr %{1}, '__float'
        %if %$__nx_strstr_pos != 0
            %assign %$__nx_isfloattok_bool 1
            %substr %%__fpnum %%__arg_str %$__nx_strstr_pos,-1
            %deftok %%__fptok %%__fpnum
            %assign %$__nx_isfloattok_num %%__fptok
            %undef  %%__fpnum
            %undef  %%__fptok
        %else
            %assign %%__found 0
            %assign %%__arg_idx 0
            %strlen %%__arg_len %%__arg_str
            %rep %%__arg_len
                %assign %%__arg_idx %%__arg_idx + 1
                %substr %%__arg_chr %%__arg_str %%__arg_idx, 1
                %assign %%__found 0
                %assign %%__idx 0
                %rep 15
                    %assign %%__idx %%__idx + 1
                    %substr %%__chr __NASMX_NUMALPHATOKEN__ %%__idx, 1
                    %ifidn %%__chr, %%__arg_chr
                        %assign %%__found %%__idx
                        %exitrep
                    %endif
                %endrep
                %if %%__found == 0
                    %exitrep
                %endif
            %endrep
            %assign %$__nx_isfloattok_bool %%__found
            %if %%__found
                %if %2 == 0
                    ;// we can only assume the number provided
                    ;// fits in the bits defined
                    %if __NASMX_ABI_BITS__ > 32
                        %assign %$__nx_isfloattok_num __float64__(%1)
                    %else
                        %assign %$__nx_isfloattok_num __float32__(%1)
                    %endif
                %elif %2 == 4
                    %assign %$__nx_isfloattok_num __float32__(%1)
                %else
                    %assign %$__nx_isfloattok_num __float64__(%1)
                %endif
            %endif
            %undef %%__arg_str
        %endif
    %endif
%endmacro

;//////////////////////////////////////////////////////////////
;// MACRO nx_ishextok
;//
;// Purpose
;//    This macro is designed to return in the current context
;//    stack variable %$__nx_ishextok_bool if the parameter is
;//    a hex token.  Note that this macro also returns true if
;//    arg is an integer making it rather useful when we need
;//    to move the number to a register
;//
;// Usage:
;//    nx_ishextok token
;//    nx_ishextok 0xFFF0
;//
%macro nx_ishextok 1.nolist
    %ifstr %1
        %define %%__arg_str %1
    %else
        %defstr %%__arg_str %1
    %endif
    %strlen %%__arg_len %%__arg_str
    %assign %%__arg_idx 0
    %assign %%__has_x 0
    %rep %%__arg_len
        %assign %%__arg_idx %%__arg_idx + 1
        %substr %%__arg_chr %%__arg_str %%__arg_idx, 1
        %assign %%__found 0
        %ifidni %%__arg_chr, 'x'
            %if %%__has_x == 0
                %if %%__arg_idx < %%__arg_len
                    %assign %%__has_x 1
                    %assign %%__found 1
                %else
                    %exitrep
                %endif
            %else
                %exitrep
            %endif
        %else
            %assign %%__idx 1
            %rep 24
                %assign %%__idx %%__idx + 1
                %substr %%__chr __NASMX_NUMALPHATOKEN__ %%__idx, 1
                %ifidn %%__chr, %%__arg_chr
                    %assign %%__found %%__idx
                    %exitrep
                %endif
            %endrep
        %endif
        %if %%__found == 0
            %exitrep
        %endif
    %endrep
    %assign %$__nx_ishextok_bool %%__found
%endmacro

;//////////////////////////////////////////////////////////////
;// MACRO nx_strtok
;//
;// Purpose
;//    To parse a string and return delimited tokens
;//    Functionality is similar to the C strtok function
;//
;// Usage:                        ; After call:
;//    nx_strtok two tokens, ' '  ; %$__nx_token = two   , %$__nx_token_len = 3
;//    nx_strtok NULL, ' :?;'     ; %$__nx_token = tokens, %$__nx_token_len = 6
;//    nx_strtok NULL, ' :?;'     ; %$__nx_token = ''    , %$__nx_token_len = 0
;//
;// Notes:
;//    The return value is stored on the context stack as
;//    %$__nx_token thus it must only be called within a valid context.
;//    The length is also returned as %$__nx_token_len.  Check this value
;//    for 0 after call this macro before processing the return value.
;//
;//    Call more than once to get the next token in the sequence, if any.
;//    This function must be called at least once with a valid string
;//    or token to parse before passing in NULL (0) in subsequent calls.
;//
;//    Unfortunately, a side effect of using macros is that a comma which
;//    appears in a token actually causes the single token to split into 2
;//    tokens making it impossible to use this macro like:
;//         %define mytoken $32,000
;//         nx_strtok mytoken, ','
%imacro nx_strtok 2.nolist
	%ifstr %2
		%define %%__sep_str %2
	%else
		%defstr %%__sep_str %2
	%endif
	%strlen %%__sep_len %%__sep_str
	%ifnum %1
		%assign %%__nx_null %1
		%if %%__nx_null == 0
			%define %%__arg_str %$__nxtok_next
			%assign %%__arg_len %$__nxtok_len
		%else
			%defstr %%__arg_str %1
			%strlen %%__arg_len %%__arg_str
		%endif
	%else
		%ifstr %1
			%define %%__tmp_str %1
		%else
			%defstr %%__tmp_str %1
		%endif
		%strlen %%__arg_len %%__tmp_str
		;// ignore leading separator tokens
		%assign %$__nx_token_len 0
		%assign %%__arg_idx 1
		%rep %%__arg_len
			%substr %%__arg_chr %%__tmp_str %%__arg_idx
			%assign %%__sep_idx 1
			%rep %%__sep_len
				%substr %%__sep_chr %%__sep_str %%__sep_idx
				%ifidn %%__arg_chr, %%__sep_chr
					%assign %$__nx_token_len %%__arg_idx
					%exitrep
				%else
					%assign %%__sep_idx %%__sep_idx + 1
				%endif
			%endrep
			%if %$__nx_token_len != 0
				%assign %%__arg_idx %%__arg_idx + 1
				%assign %$__nx_token_len 0
			%else
				%exitrep
			%endif
		%endrep

		%if %%__arg_idx > 1
			%if %%__arg_idx <= %%__arg_len
				%assign %%__sublen %%__arg_len - %%__arg_idx + 1
				%substr %%__arg_str %%__tmp_str %%__arg_idx, %%__sublen
				%strlen %%__arg_len %%__arg_str
			%else
				%assign %%__arg_len 0
			%endif
		%else
			%xdefine %%__arg_str %%__tmp_str
			%strlen %%__arg_len %%__arg_str
		%endif
	%endif

	%assign %$__nx_token_len 0
	%if %%__arg_len == 0
		%define %$__nxtok_next ''
		%assign %$__nxtok_len 0
		%define %$__nx_token ''
	%else
		%assign %%__arg_idx 1
		%rep %%__arg_len
			%substr %%__arg_chr %%__arg_str %%__arg_idx
			%assign %%__sep_idx 1
			%rep %%__sep_len
				%substr %%__sep_chr %%__sep_str %%__sep_idx
				%ifidn %%__arg_chr, %%__sep_chr
					%assign %$__nx_token_len %%__arg_idx-1
					%exitrep
				%else
					%assign %%__sep_idx %%__sep_idx + 1
				%endif
			%endrep
			%if %$__nx_token_len != 0
				%exitrep
			%else
				%assign %%__arg_idx %%__arg_idx + 1
			%endif
		%endrep
		%if %$__nx_token_len == 0
			%deftok %$__nx_token %%__arg_str
			%assign %$__nx_token_len %%__arg_len
			%define %$__nxtok_next ''
			%assign %$__nxtok_len 0
		%else
			%substr %%__tokstr %%__arg_str 1,%$__nx_token_len
			%deftok %$__nx_token %%__tokstr
			%if %$__nx_token_len < %%__arg_len
				%rep %%__arg_len - %$__nx_token_len
					%substr %%__arg_chr %%__arg_str %%__arg_idx
					%assign %%__nx_found 0
					%assign %%__sep_idx 1
					%rep %%__sep_len
						%substr %%__sep_chr %%__sep_str %%__sep_idx
						%ifidn %%__arg_chr, %%__sep_chr
							%assign %%__nx_found 1
							%exitrep
						%else
							%assign %%__sep_idx 1+%%__sep_idx
						%endif
					%endrep
					%if %%__nx_found == 0
						%exitrep
					%else
						%assign %%__arg_idx 1+%%__arg_idx
					%endif
				%endrep
				%if %%__arg_idx <= %%__arg_len
					%assign %$__nxtok_len %%__arg_len-%%__arg_idx+1
					%substr %$__nxtok_next %%__arg_str %%__arg_idx,%$__nxtok_len
				%else
					%define %$__nxtok_next ''
					%assign %$__nxtok_len 0
				%endif
			%else
				%define %$__nxtok_next ''
				%assign %$__nxtok_len 0
			%endif
		%endif
	%endif

%endmacro


;//////////////////////////////////////////////////////////////
;// MACRO nx_strchr
;//
;// Purpose
;//    This macro is designed to find position of char within string.
;//    It will update the current context stack variable %$__nx_strchr_pos
;//    with the index position of the chr or 0 if chr not found
;// Usage:
;//    nx_strchr string, chr
;//    nx_strchr [wc + hInstance], 'x'
;//
%macro nx_strchr 2.nolist
	%ifdef %$__nx_strchr_string
		%undef %$__nx_strchr_string
	%endif
	%ifstr %1
		%xdefine %$__nx_strchr_string %{1}
	%else
		%defstr %$__nx_strchr_string %{1}
	%endif
	%strlen %%__count %[%$__nx_strchr_string]
	%assign %%__idx 0
	%assign %%__found 0
	%rep %%__count
		%assign %%__idx %%__idx + 1
		%substr %%__chr %[%$__nx_strchr_string] %%__idx
		%ifidn %%__chr,%{2}
			%assign %%__found %%__idx
			%exitrep
		%endif
	%endrep
	%assign %$__nx_strchr_pos %%__found
%endmacro


;//////////////////////////////////////////////////////////////
;// MACRO nx_strstr
;//
;// Purpose
;//    This macro is designed to find position of substr within string.
;//    It will update the current context stack variable %$__nx_strstr_pos
;//    with the index position of the substr or 0 if not found
;// Usage:
;//    nx_strstr string, substr
;//    nx_strstr [rpb + hInstance], rbp
;//
%macro nx_strstr 2.nolist
	%ifdef %$__nx_strstr_string
		%undef %$__nx_strstr_string
	%endif
	%ifstr %1
		%xdefine %$__nx_strstr_string %{1}
	%else
		%defstr %$__nx_strstr_string %{1}
	%endif
	%ifstr %2
		%xdefine %$__nx_strstr_substring %{2}
	%else
		%defstr %$__nx_strstr_substring %{2}
	%endif
	%strlen %%__count %[%$__nx_strstr_string]
	%substr %%__subchr %[%$__nx_strstr_substring] 1
	%strlen %%__sublen %[%$__nx_strstr_substring]
	%assign %%__idx 0
	%assign %%__found 0
	%rep %%__count
		%assign %%__idx %%__idx + 1
		%if ((%%__count - %%__idx + 1) < %%__sublen)
			%exitrep
		%else
			%substr %%__chr %[%$__nx_strstr_string] %%__idx
			%ifidni %%__chr,%%__subchr
				%substr %%__tmpstr %$__nx_strstr_string %%__idx, %%__sublen
				%ifidni %%__tmpstr, %$__nx_strstr_substring
					%assign %%__found %%__idx
					%exitrep
				%endif
			%endif
		%endif
	%endrep
	%assign %$__nx_strstr_pos %%__found
	%undef %$__nx_strstr_string
	%undef %$__nx_strstr_substring
%endmacro


;// small helper macro used to parse __nxsig@@ defines
%macro nx_parse_tokens 1-100.nolist
	%ifdef __nx_token_0
		%undef __nx_token_0
	%endif
	%xdefine __nx_token_0 %0
	%assign %%__ctr 1
	%rep %0
		%ifdef __nx_token_%[%%__ctr]
			%undef __nx_token_%[%%__ctr]
		%endif
		%xdefine __nx_token_%[%%__ctr] %1
		%assign %%__ctr 1 + %%__ctr
		%rotate 1
	%endrep
%endmacro


;//////////////////////////////////////////////////////////////
;// MACRO IMPORT
;//
;// Purpose
;//    To define the signature and required syntax for
;//    an external function
;//
;// usage:
;//    IMPORT printf
;//    IMPORT GetSystemWindowsDirectoryA, 8
;//    IMPORT cdecl, myfunc, ptrdiff_t, dword, float_t
;//
%imacro IMPORT 1-100.nolist
	%push __NX_CTX_IMPORT__

	%assign %$__bytecount 0
	%ifndef __NASMX_DECLSPEC_CALLCONV_%[%1]__
		%assign %$__callconv __NASMX_DECLSPEC_CALLCONV_DEFAULT__
		%define %$__nx_proc %1
		%if %0 > 1
			%ifnum %2
				%ifidn __OUTPUT_FORMAT__,win32
					%assign %$__bytecount %2
				%endif
				%assign %$__repargs 0
			%else
				%assign %$__repargs %0-1
			%endif
		%else
			%assign %%__cc_enum nx_declspec_cc_enum(__NASMX_DECLSPEC_CALLCONV_DEFAULT__)
			%if %%__cc_enum == __NASMX_DECLSPEC_CC_ENUM_STDCALL__
				;// assert: no bytecount in import implies cdecl for win32
				%assign %$__callconv __NASMX_DECLSPEC_CALLCONV_CDECL__
;			%elif %%__cc_enum == __NASMX_DECLSPEC_CC_ENUM_FASTCALL__
;				;// assert: no bytecount in import implies cdecl for win32/win64 fastcall
;				%assign %$__callconv __NASMX_DECLSPEC_CALLCONV_CDECL__
			%endif
			%assign %$__repargs 0
		%endif
	%else
		%if %0 < 2
			%fatal usage: IMPORT [CALLCONV, ] FUNCNAME [,ARG1,ARG2,...]
		%endif
		%assign %$__callconv __NASMX_DECLSPEC_CALLCONV_%[%1]__
		%define %$__nx_proc %2
		%assign %$__repargs %0-2
	%endif

	%ifdef __nx_import_param_list
		%undef __nx_import_param_list
	%endif
	%assign %%__cc_enum nx_declspec_cc_enum(%[%$__callconv])
	%if %%__cc_enum != __NASMX_DECLSPEC_CC_ENUM_NAKED__
		;// assert: calc byte count for sig check
		%rep %$__repargs
			%rotate -1
			%ifnum %1
				%assign %$__bytecount %1
				%exitrep
			%else
				nx_strtok %1, ' '
				%assign %%__param_size sizeof(%$__nx_token)
				%if %%__param_size < sizeof(size_t)
					%assign %%__param_size sizeof(size_t)
				%endif
				%if %%__param_size > (sizeof(size_t) * 2)
					%error %1 exceeds allowable parameter size
				%endif
				%assign %$__bytecount %$__bytecount + %%__param_size
				%xdefine __nx_import_argtype %$__nx_token %+ __nx_type
				%ifndef __nx_import_param_list
					%defstr __nx_import_param_list __nx_import_argtype
				%else
					%defstr __nx_import_argstr __nx_import_argtype
					%strcat __nx_import_param_list __nx_import_argstr,',',__nx_import_param_list
					%undef __nx_import_argstr
				%endif
				%undef __nx_import_argtype
			%endif
		%endrep
	%endif
	nx_callconv_decorate %$__callconv,%$__nx_proc,%$__bytecount
	%ifdef __nxsig@@%[%$__nxtok_decorated_name]
		%warning redefining import symbol %$__nx_proc as %[%$__nxtok_decorated_name]
	%endif

	%ifndef __nx_import_param_list
		%xdefine __nxsig@@%[%$__nxtok_decorated_name] %[%$__callconv],%[%$__bytecount]
	%else
		%deftok __nx_import_params __nx_import_param_list
		%xdefine __nxsig@@%[%$__nxtok_decorated_name] %[%$__callconv],%[%$__bytecount],__nx_import_params
		%undef __nx_import_params
		%undef __nx_import_param_list
	%endif
	%ifnidn %$__nx_proc,%$__nxtok_decorated_name
		%xdefine %[%$__nx_proc] %[%$__nxtok_decorated_name]
	%endif

	%pop
%endmacro


;//////////////////////////////////////////////////////////////
;// MACRO PROTO
;//
;// usage:
;//    PROTO [CALLCONV,] FUNCNAME [,ARGS...]
;//
;// examples:
;// Using default calling convention:
;//    PROTO WndProc, ptrdiff_t, dword, size_t, size_t
;// Specifying a calling convention
;//    PROTO cdecl, myfunc, ptrdiff_t, dword, float_t
;//
;// notes:
;//    This macro must be used when defining procedures
;//    that will be callable from other modules via
;//    the import macro as the function name is made
;//    global here.
;//
%imacro PROTO 1-100.nolist
	%push __NX_CTX_PROTO__
	%ifndef __NASMX_DECLSPEC_CALLCONV_%[%1]__
		%assign %$__callconv __NASMX_DECLSPEC_CALLCONV_DEFAULT__
		%define %$__proc %1
		%assign %$__repcnt %0-1
	%else
		%if %0 < 2
			%fatal usage: PROTO [CALLCONV, ] FUNCNAME [,ARG1,ARG2,...]
		%endif
		%assign %$__callconv __NASMX_DECLSPEC_CALLCONV_%[%1]__
		%define %$__proc %2
		%assign %$__repcnt %0-2
	%endif
	%ifdef __nx_proto_param_list
		%undef __nx_proto_param_list
	%endif
	%assign %$__bytecount 0
	%assign %%__cc_enum nx_declspec_cc_enum(%$__callconv)
	%if %%__cc_enum != __NASMX_DECLSPEC_CC_ENUM_NAKED__
		;// assert: calc byte count for sig check during invoke 
		%rep %$__repcnt
			%rotate -1
			%ifnum %1
				%assign %$__bytecount %1
				%exitrep
			%else
				nx_strtok %1, ' '
				%assign %%__param_size %[%$__nx_token]_size
				%if %%__param_size < sizeof(size_t)
					%assign %%__param_size sizeof(size_t)
				%endif
				%if %%__param_size > (sizeof(size_t) * 2)
					%error %1 exceeds allowable parameter size
				%endif
				%assign %$__bytecount %$__bytecount + %%__param_size
				%xdefine __nx_proto_argtype %$__nx_token %+ __nx_type
				%ifndef __nx_proto_param_list
					%defstr __nx_proto_param_list __nx_proto_argtype
				%else
					%defstr __nx_proto_argstr __nx_proto_argtype
					%strcat __nx_proto_param_list __nx_proto_argstr,',',__nx_proto_param_list
					%undef __nx_proto_argstr
				%endif
				%undef __nx_proto_argtype
			%endif
		%endrep
	%endif

	%ifndef %[%$__proc]
		%ifdef __nxsig@@%[%$__proc]
			%fatal global symbol %[%$__proc] already defined
		%endif
		nx_callconv_decorate %$__callconv,%$__proc,%$__bytecount
		%ifndef __nx_proto_param_list
			%xdefine __nxsig@@%[%$__nxtok_decorated_name] %[%$__callconv],%[%$__bytecount]
		%else
			%deftok __nx_proto_params __nx_proto_param_list
			%xdefine __nxsig@@%[%$__nxtok_decorated_name] %[%$__callconv],%[%$__bytecount],__nx_proto_params
			%undef __nx_proto_params
			%undef __nx_proto_param_list
		%endif
		%ifnidn %$__proc,%$__nxtok_decorated_name
			%xdefine %[%$__proc] %[%$__nxtok_decorated_name]
		%endif
	%endif

	%ifndef __nxsig_declared_%[%$__proc]
		global %[%$__proc]
		%xdefine __nxsig_declared_%[%$__proc] global
	%endif

	%pop
%endmacro


;//////////////////////////////////////////////////////////////
;// MACRO ENTRY
;//
;// usage:
;//    ENTRY progname
;//
;// examples:
;//    ENTRY Demo1
;//
;// notes:
;//    program entry is assumed to be cdecl unless system default
;//    callconv specification is pascal.
;//    When building on Win64 or using pascal callconv you must
;//    change the makefile by removing the leading underscore
;//    from the linker /entry line
%imacro ENTRY 1.nolist
	%assign %%__cc_enum nx_declspec_cc_enum(__NASMX_DECLSPEC_CALLCONV_DEFAULT__)
	%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
		;// main(argc, argv)
		%assign %%__bytecount __NASMX_ABI_BITS__ / 4
	%else
		;// main(argc, argv, envp)
		%assign %%__bytecount (( __NASMX_ABI_BITS__ / 8 ) * 3)
	%endif
	
	%if %%__cc_enum > __NASMX_DECLSPEC_CC_ENUM_PASCAL__
		%assign %%__cc_prefix nx_declspec_cc_prefix(__NASMX_DECLSPEC_CALLCONV_DEFAULT__)
		%if %%__cc_prefix > 0
			%xdefine %[%1] _main
			%xdefine __nxsig@@_main  __NASMX_DECLSPEC_CALLCONV_CDECL__, %%__bytecount
		%else
			%xdefine %[%1] main
			%xdefine __nxsig@@main  __NASMX_DECLSPEC_CALLCONV_DEFAULT__, %%__bytecount
		%endif
	%else
		%xdefine %[%1] main
		%xdefine __nxsig@@main  __NASMX_DECLSPEC_CALLCONV_DEFAULT__, %%__bytecount
	%endif
	%xdefine __nxsig_declared_%[%1] global
	global %[%1]
%endmacro

;////////////////////////////////////////////////////////////////////////
;//
;// Internal macro used by invoke to detect argv addressing mode
;// The context variable %$__nx_argv_mode_indirect will be set to
;// the string index where '[' is found and is also used as a flag
;// indicating retrieve the variable contents, not it's address.
;// The context variable %$__nx_argv_mode_bp will be set to the
;// the string index where the sign ( + or - ) is found and will
;// be used as a flag indicating that argv mode is used.
;// The context variables %$__nx_argv_mode_param_type, %$__nx_argv_mode_param_isfloat,
;// %$__nx_argv_mode_param_size, and %$__nx_argv_mode_param_castsize are set according
;// to the parameter list index supplied as the second argument to this macro.
%xdefine __NX_ARGV_MODE_SIGN_ADD__ 1
%xdefine __NX_ARGV_MODE_SIGN_SUB__ 2
%macro nx_analyze_argv_mode 2
	%ifnum %2
		%ifdef __nx_token_%[%2]
			%assign %$__nx_argv_mode_param_type __nx_token_%[%2]
			%assign %$__nx_argv_mode_param_isfloat ((%$__nx_argv_mode_param_type >> 15) & 0x01)
			%assign %$__nx_argv_mode_param_size %$__nx_argv_mode_param_type & 0x7F
		%else
			%assign %$__nx_argv_mode_param_type sizeof(size_t)
			%assign %$__nx_argv_mode_param_isfloat 0
			%assign %$__nx_argv_mode_param_size sizeof(size_t)
		%endif
	%else
		%fatal internal error - unknown parameter
	%endif

	%assign %$__nx_argv_mode_bp 0
	%assign %$__nx_argv_mode_sign 0
	%assign %$__nx_argv_mode_castsize sizeof(size_t)
	%assign %$__nx_argv_mode_fp_isnum 0
	%assign %$__nx_argv_mode_fp_num 0
	nx_strchr %{1}, '['
	%assign %$__nx_argv_mode_indirect %$__nx_strchr_pos
	%if %$__nx_argv_mode_indirect == 0
		nx_strstr %{1}, __BP
		%if %$__nx_strstr_pos > 0
			;// assert: potentially loading variable address offset from reg bp
			;// quick check to help ensure that bp is a token
			%assign %$__nx_isalnum_bool 0
			%defstr %%__str %[%1]
			%if %$__nx_strstr_pos > 1
				%substr %%__sub %%__str %$__nx_strstr_pos-1, 1
				nx_isalnum %%__sub
			%endif
			%if %$__nx_isalnum_bool == 0
				%strlen %%__len %%__str
				%if %%__len > %$__nx_strchr_pos + 2
					%substr %%__sub %%__str %$__nx_strstr_pos+3, 1
					nx_isalnum %%__sub
				%endif
			%endif
			%if %$__nx_isalnum_bool == 0
				;// we must be given a positive or negative offset in order to 
				;// generate code for local variable addressing
				nx_strchr %{1}, '+'
				%if %$__nx_strchr_pos == 0
					nx_strchr %{1}, '-'
					%if %$__nx_strchr_pos > 0
						%assign %$__nx_argv_mode_sign __NX_ARGV_MODE_SIGN_SUB__
					%endif
				%else
					%assign %$__nx_argv_mode_sign __NX_ARGV_MODE_SIGN_ADD__
				%endif
				%assign %$__nx_argv_mode_bp %$__nx_strchr_pos
			%endif
			%substr %%__off %%__str %$__nx_argv_mode_bp+1, -1
			%deftok %$__nx_argv_mode_bp_offset %%__off
		%elif %$__nx_argv_mode_param_isfloat > 0
			;// assert: check for float type and process
			nx_isfloattok %1, %$__nx_argv_mode_param_size
			%if %$__nx_isfloattok_bool != 0
				%assign %$__nx_argv_mode_fp_isnum 1
				%assign %$__nx_argv_mode_fp_num %$__nx_isfloattok_num
			%else
				nx_strtok %1, ' '
				%ifndef __nx_reg_%[%$__nx_token]
					%assign %$__nx_strstr_pos 0
					%if __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__ > 0
						nx_strstr __NASMX_DECLSPEC_FASTCALL_REGFLOATARGS_%[%$__nx_argv_mode_castsize]__,%$__nx_token
					%endif
					%if %$__nx_strstr_pos == 0
						%iftoken %1
							%fatal expected floating point at arg %1
						%endif
						;// must check for casts which indicate
						;// __float() or __double() may have been used
						%ifdef %[%$__nx_token]_size
							%assign %%__size %[%$__nx_token]_size
							nx_strtok 0, ';'
						%else
							%assign %%__size %$__nx_argv_mode_param_size
							nx_strtok %1, ';'
						%endif
						%if %%__size > %$__nx_argv_mode_param_size
							%warning potential loss of precision from double to float for arg %1
						%endif
						%assign %$__nx_argv_mode_fp_isnum 1
						%assign %$__nx_argv_mode_fp_num %$__nx_token
					%endif
				%endif
			%endif
		%endif
	%elif %$__nx_argv_mode_indirect > 3
		;// check for cast ( eg: dword[rbp+4] )
		%defstr %%__str %[%1]
		%substr %%__sub %%__str 1, %$__nx_argv_mode_indirect-1
		%deftok %%__tok %%__sub
		%ifdef %[%%__tok]_size
			%assign %$__nx_argv_mode_castsize %[%%__tok]_size
		%endif
	%endif
%endmacro

;//////////////////////////////////////////////////////////////
;// MACRO INVOKE
;//
;// usage:
;//    INVOKE func [, arg1] [,arg2]
;//
;// examples:
;//    invoke malloc, 64
;//
;// notes:
;//    when using bp offsets you should use qualifiers to ensure
;//    they are passed properly, ie: invoke malloc, dword [argv(.x)]
;//
%imacro INVOKE 1-100.nolist
	%ifndef NASMX_ENDPROC
		;// assert: we cannot check for context in case we are in a switch
		;// so we use nasmx_endproc
		%fatal 'invoke must be contained within proc/endproc directives.'
	%endif
	%ifndef __NX_LOCALS_PRESENT__
		;// require locals directive to ensure stack
		;// frame initialized properly prior to invoke.
		%fatal 'missing locals directive'
	%endif

	%push _NX_CTX_INVOKE
	%assign %$args 0
	%assign %$__nx_intargs 0           ;// init int args counter
	%assign %$__nx_floatargs 0         ;// init float args counter

	;// Fix for v1.0rc2: an imported definition may be zero (0)
	;// for CDECL varargs or not properly defined, thus we must
	;// calculate a valid bytecount based upon given parameters
	;// in order to get a proper stack frame built if callstack
	;// not defined.
	%ifdef __nxsig@@%[%1]
		nx_parse_tokens __nxsig@@%[%1]
		%assign %$__nx_callconv __nx_token_1
		%assign %$__nx_protobytecount __nx_token_2
		%ifndef __nxsig_declared_%[%1]
			%ifndef __nxsig_defined_%[%1]
				EXTERN	%[%1]
				%xdefine __nxsig_declared_%[%1] extern
			%endif
		%endif
	%else
		%assign %$__nx_callconv __NASMX_DECLSPEC_CALLCONV_DEFAULT__
		%assign %$__nx_protobytecount 0
	%endif

	%assign %%__nx_argrotate nx_declspec_cc_argrotate(%$__nx_callconv)
	%if %%__nx_argrotate > 0
		%assign %$__nx_argrotate 1
	%else
		%assign %$__nx_argrotate -1
	%endif

	%assign %$__nx_retpopsargs nx_declspec_cc_retpopsargs(%$__nx_callconv)
	%assign %%__cc_enum nx_declspec_cc_enum(%$__nx_callconv)
	%xdefine %$__nx_proc %1

	;// NASMX 1.4 - The following was added to compensate for the fact
	;// that the user may pass __AX in an argument and thus we may need
	;// to save/restore __AX as it is used to spill arguments to the stack.
	%assign %$__reg_ax_used 0
	%assign %$__reg_ax_saved 0
	%assign %%__repcnt 0   ; assume no reg ax checking
	%if %0 > 1
		%assign %%__repcnt %0 - 1
		%if %%__cc_enum == __NASMX_DECLSPEC_CC_ENUM_FASTCALL__
			%assign %%__arg_rotate 1
			%assign %%__maxregs __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__
			%if %%__repcnt > %%__maxregs
				%assign %%__repcnt %%__maxregs
			%endif
			%rep %%__repcnt
				%rotate %%__arg_rotate
				;// assert: must check for float tokens since
				;// __AX will be used to load stack
				nx_isfloattok %{1}
				%if %$__nx_isfloattok_bool != 0
					%if %$__reg_ax_used != 0
						%assign %$__reg_ax_saved 1
					%endif
					%assign %$__reg_ax_used %$__reg_ax_used + 1
				%elifidni %{1},__AX
					%if %$__reg_ax_used != 0
						%assign %$__reg_ax_saved 1
					%endif
				%endif
			%endrep
			%rotate %%__arg_rotate
			%assign %%__repcnt %0 - 1
			%if %%__repcnt > %%__maxregs
				%assign %%__repcnt %%__repcnt - %%__maxregs
			%else
				%assign %%__repcnt 0
			%endif
		%else
			%assign %%__arg_rotate %$__nx_argrotate
			%rotate %%__arg_rotate
		%endif
	%endif
	%if %%__repcnt != 0
		%rep %%__repcnt
			%assign %$__nx_strchr_pos 0
			%assign %%__parse_arg 0
			%ifnum %{1}
				%if __NASMX_ABI_BITS__ > 32
					%assign %$__reg_ax_used %$__reg_ax_used + 1
				%endif
			%elifstr %{1}
				%if __NASMX_ABI_BITS__ > 32
					%assign %$__reg_ax_used %$__reg_ax_used + 1
				%endif
			%elifidni %{1},__AX
				%if %$__reg_ax_used != 0
					%assign %$__reg_ax_saved 1
				%endif
			%else
				nx_strchr %{1},'['
				%if %$__nx_strchr_pos != 0
					%if %$__reg_ax_used != 0
						%assign %$__reg_ax_saved 1
					%endif
					%assign %$__reg_ax_used %$__reg_ax_used + 1
				%else
					nx_isfloattok %{1}
					%if %$__nx_isfloattok_bool != 0
						%if __NASMX_ABI_BITS__ > 32
							%if %$__reg_ax_used != 0
								%assign %$__reg_ax_saved 1
							%endif
							%assign %$__reg_ax_used %$__reg_ax_used + 1
						%endif
					%else
						%assign %%__parse_arg 1
					%endif
				%endif
			%endif

			%if %%__parse_arg != 0
				;// parse this argument looking for __AX
				%assign %%__tokctr 0
				%assign %%__saw_ax 0
				%assign %%__saw_reg 0
				nx_strtok %{1},' -+*/%'
				%rep 8
					%if %$__nx_token_len == 0
						%exitrep
					%else
						%assign %%__tokctr %%__tokctr + 1
						%if %$__nx_token_len == 3
							nx_strstr %$__nx_token,__AX
							%if %$__nx_strstr_pos != 0
								%assign %%__saw_ax 1
								%if %$__reg_ax_used != 0
									%assign %$__reg_ax_saved 1
								%endif
							%elifdef __nx_reg_%[%$__nx_token]
								%assign %%__saw_reg 1
							%endif
						%endif
						nx_strtok 0,' -+*/%'
					%endif
				%endrep
				%if %%__saw_reg != 0
					;// we don't support the combination of
					;// REG and AX for calculating offset.
					%if %%__saw_ax != 0
						%fatal loading __AX with invalid arg: %1
					%endif
					%if %%__tokctr > 1
						%assign %$__reg_ax_used %$__reg_ax_used + 1
					%endif
				%endif
			%endif
			%rotate %%__arg_rotate
		%endrep
	%endif

	%assign %%__repcnt %0 - 1
	%assign %$__nx_bytecount (( __NASMX_ABI_BITS__ / 8 ) * %%__repcnt)
	%if %$__nx_bytecount < %$__nx_protobytecount
		;// assert: possibly due to double param in
		;// 32bit mode or int128 in 64bit mode
		%assign %$__nx_bytecount %$__nx_protobytecount
	%endif

	%if %%__cc_enum == __NASMX_DECLSPEC_CC_ENUM_FASTCALL__
		;// for fastcall, whenever CALLSTACK optimization is enabled,
		;// we use the stack built previously during locals/endlocals directive.
		%assign %$__nx_callstack_adjust 0
		%assign %$__nx_invoke_callstack_adjust %$__nx_bytecount
		%ifdef __NX_PROLOGUE_CALLSTACK_ADJUST__
			;// Verify that the CALLSTACK is sufficient for the
			;// number of parameter arguments we have been given.
			%assign %$__nx_callstack_adjust __NX_PROLOGUE_CALLSTACK_ADJUST__
			%if __NASMX_ABI_BITS__ < 64
				%if %$__nx_callstack_adjust < %$__nx_bytecount
					%assign %$__nx_callstack_adjust 0
					%warning insufficient callstack size for procedure %[%$__nx_proc], generating inefficient code...
				%endif
			%else
				%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
					%if %$__nx_callstack_adjust < %$__nx_bytecount
						;// Windows: always requires a stack adjustment
						%assign %$__nx_callstack_adjust 0
						%warning insufficient callstack size for procedure %[%$__nx_proc], generating inefficient code...
					%else
						;// A callstack defined for Win64 must be at least 32 bytes
						%if %$__nx_callstack_adjust < 32
							%assign %$__nx_callstack_adjust 0
							%warning insufficient callstack size for procedure %[%$__nx_proc], generating inefficient code...
						%else
							%assign %$__nx_invoke_callstack_adjust 0
						%endif
					%endif
				%else
					;// Linux: required when register allocation exhausted
					%if %%__repcnt > 6
						%assign %$__nx_invoke_callstack_adjust (( %%__repcnt - 6 ) * ( __NASMX_ABI_BITS__ / 8 ))
						%if %$__nx_invoke_callstack_adjust > %$__nx_callstack_adjust
							%assign %$__nx_callstack_adjust 0
							%warning insufficient callstack size for procedure %[%$__nx_proc], generating inefficient code...
						%else
							%assign %$__nx_invoke_callstack_adjust 0
						%endif
					%else
						%assign %$__nx_invoke_callstack_adjust 0
					%endif
				%endif
			%endif
		%else
			%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ != __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
				%if __NASMX_ABI_BITS__ > 32
					;// Make space for x64 args that could possibly get placed onto the stack
					%if %%__repcnt > 6
						;// TODO: Make more efficient by examining param types ( non-trivial ).
						%assign %$__nx_invoke_callstack_adjust (( %%__repcnt - 6 ) * ( __NASMX_ABI_BITS__ / 8 ))
					%else
						%assign %$__nx_invoke_callstack_adjust 0
					%endif
				%endif
			%endif
		%endif

		%assign %$__align 0
		%if %$__nx_invoke_callstack_adjust > 0
			;// assert: callstack not defined or insufficient, build it here
			%if __NASMX_ABI_BITS__ > 32
				%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
					;// Windows requires at least 32 bytes of shadow storage
					%if %$__nx_invoke_callstack_adjust < 32
						%assign %$__nx_invoke_callstack_adjust 32
					%endif
				%endif
			%endif
			;// first determine if an alignment adjustment is needed
			%assign %$__align __NASMX_ABI_BITS__ / 4
			%assign %%__off (((%$__nx_invoke_callstack_adjust + %$__align) / %$__align) * %$__align)
			%assign %%__tmp (%$__nx_invoke_callstack_adjust + %$__align)
			%if (%%__off != %%__tmp)
				;// for fastcalls that retpopsargs we need to account
				;// for the extra space when stack restored later on
				%assign %$__align __NASMX_ABI_BITS__ / 8
				%assign %$__nx_invoke_callstack_adjust %%__off
			%else
				%assign %$__align 0
			%endif
			sub __SP, %$__nx_invoke_callstack_adjust
		%endif

		%if %$__reg_ax_saved != 0
			mov size_t [__SP - __NASMX_ABI_BITS__ / 8], __AX
		%endif

		%assign %$__param_type_ctr 2    ; arg types follow cconv,bytecount
		%assign %$args 0
		%assign %%targ 1
		%rep %%__repcnt
			%rotate 1
			%assign %%targ (%%targ + 1)

			;// set up internal vars used to determine if argv address mode used
			%assign %$__param_type_ctr %$__param_type_ctr + 1
			nx_analyze_argv_mode %1, %$__param_type_ctr

			%assign %%__argtostack 1  ;// assume we need to store on stack
			%if %$__nx_argv_mode_param_isfloat == 0
				%if %$__nx_intargs < __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__
					%assign %%__argtostack 0
					%substr %%__regstr __NASMX_DECLSPEC_FASTCALL_REGINTARGS_%[%$__nx_argv_mode_castsize]__ (%$__nx_intargs * 3 + 1), 3
					%deftok %$arg_cur %%__regstr
					%undef %%__regstr
					%ifnum %1
						%if %1 == -1
							or %$arg_cur, %1
						%elif %1 == 0
							xor %$arg_cur, %$arg_cur
						%else
							mov %$arg_cur, %1
						%endif
					%elifstr %1
						jmp %%endstr_%$args
						%%str_%$args: declare(NASMX_TCHAR) NASMX_TEXT(%1), 0
						%%endstr_%$args:
						lea %$arg_cur,[rel %%str_%$args]
					%else
						%if %$__nx_argv_mode_indirect > 0
							mov  %$arg_cur, %1
						%elif %$__nx_argv_mode_bp > 0
							mov  %$arg_cur, __BP
							%if %$__nx_argv_mode_sign == __NX_ARGV_MODE_SIGN_ADD__
								add %$arg_cur, %$__nx_argv_mode_bp_offset
							%elif %$__nx_argv_mode_sign == __NX_ARGV_MODE_SIGN_SUB__
								sub %$arg_cur, %$__nx_argv_mode_bp_offset
							%else
								%fatal Unknown addressing mode for %{1}
							%endif
						%elifnidni %$arg_cur, %1
							;// if register parameter then guard against
							;// invalid register to register moves
							%ifdef __nx_reg_%[%1]
								%if %[%1]_size != __NASMX_ABI_BITS__ / 8
									%fatal %1 cannot be used as parameter for __NASMX_ABI_BITS__ bit mode
								%endif
							%endif
							mov  %$arg_cur, %1
						%endif
					%endif
					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						;// Windows fastcall uses one index for param count which
						;// indexes either int or float for purpose of preloading regs
						%assign %$__nx_floatargs 1 + %$__nx_floatargs

						;// Only spill registers if user specifies
						%ifdef ENABLE_INVOKE_FASTCALL_STACK_PRELOAD
							mov [__SP + %$args], %$arg_cur
						%endif

						;// Unlike Linux/BSD x64 all current 32-bit and 64-bit versions
						;// of Windows increase arg stack offset.
						%assign %$args %$args + sizeof(size_t)
					%else
						;// increase arg stack offset only for 32-bit non-Windows systems.
						%if __NASMX_ABI_BITS__ < 64
							%assign %$args %$args + sizeof(size_t)
						%endif
					%endif
					%assign %$__nx_intargs 1 + %$__nx_intargs
					%undef %$arg_cur
				%endif
			%elif %$__nx_floatargs < __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__
				%assign %%__argtostack 0
				%if __NASMX_ABI_BITS__ > 32
					%substr %%__regstr __NASMX_DECLSPEC_FASTCALL_REGFLOATARGS_8__ (%$__nx_floatargs * 4 + 1), 4
					%deftok %$arg_cur %%__regstr
					%undef %%__regstr

					%ifnum %1
						mov __AX, %1
						mov size_t [__SP - __NASMX_ABI_BITS__ / 4 ], __AX
						movsd %$arg_cur, size_t [__SP - __NASMX_ABI_BITS__ / 4 ]
						%if %$__reg_ax_saved != 0
							mov __AX, size_t [__SP - __NASMX_ABI_BITS__ / 8]
						%endif
					%elif %$__nx_argv_mode_indirect > 0
						nx_strtok %1, ' '
						%ifdef %[%$__nx_token]_size
							nx_strtok 0, ';'
							movsd %$arg_cur, %$__nx_token
						%else
							movsd %$arg_cur, %1
						%endif
					%elif %$__nx_argv_mode_bp > 0
						nx_strtok %1, ' '
						%ifdef __nx_reg_%[%$__nx_token]
							movsd %$arg_cur, [%1]
						%elifdef %[%$__nx_token]_size
							nx_strtok 0, ';'
							movsd %$arg_cur, [ %[%$__nx_token] ]
						%else
							movsd %$arg_cur, [%1]
						%endif
					%else
						nx_strtok %1, ' '
						%ifdef __nx_reg_%[%$__nx_token]
							mov size_t [__SP - __NASMX_ABI_BITS__ / 4 ], %1
							movsd %$arg_cur, size_t [__SP - __NASMX_ABI_BITS__ / 4 ]
						%elif %$__nx_argv_mode_fp_isnum != 0
							mov __AX, %1
							mov size_t [__SP - __NASMX_ABI_BITS__ / 4 ], __AX
							movsd %$arg_cur, size_t [__SP - __NASMX_ABI_BITS__ / 4 ]
							%if %$__reg_ax_saved != 0
								mov __AX, size_t [__SP - __NASMX_ABI_BITS__ / 8]
							%endif
						%else
							nx_strstr __NASMX_DECLSPEC_FASTCALL_REGFLOATARGS_8__,%1
							%if %$__nx_strstr_pos != 0
								%ifnidni %$arg_cur,%1
									movq %$arg_cur,%1
								%endif
							%else
								movsd %$arg_cur, %1
							%endif
						%endif
					%endif

					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						;// Only spill Win64 float register if user specifies
						%ifdef ENABLE_INVOKE_FASTCALL_STACK_PRELOAD
							movsd [__SP + %$args], %$arg_cur
						%endif

						;// Unlike Linux/BSD x64 all current 32-bit and 64-bit versions
						;// of Windows increase arg stack offset.
						%assign %$args %$args + sizeof(size_t)
					%endif
				%else
					;// 32-bit fastcall float param
					%if %$__nx_argv_mode_param_size > 4
						;// assert: callee expecting double type which
						;// is always maintained on the stack
						%if %$__nx_argv_mode_fp_isnum != 0
							%assign %%__tmp (%$__nx_argv_mode_fp_num & 0x00000000FFFFFFFF)
							mov dword [__SP + %$args], %%__tmp
							%assign %%__tmp ((%$__nx_argv_mode_fp_num >> 32) & 0x00000000FFFFFFFF)
							mov dword [__SP+%$args+4], %%__tmp
						%else
							fld %1
							fstp qword [esp]
						%endif
						%assign %$args %$args + 8
					%else
						%assign %%__reg_eax_used 0
						%if   %$args == 0
							%xdefine %$arg_cur ecx
						%elif %$args == 4
							%xdefine %$arg_cur edx
						%else
							%xdefine %$arg_cur eax
							%assign %%__reg_eax_used 1
						%endif
						%if %$__nx_argv_mode_fp_isnum != 0
							mov %$arg_cur, %$__nx_argv_mode_fp_num
						%else
							mov %$arg_cur, %1
						%endif
						mov [__SP + %$args], %$arg_cur
						%if %%__reg_eax_used != 0
							%if %$__reg_ax_saved != 0
								mov eax, dword [esp - 4]
							%endif
						%endif
						%assign %$args %$args + 4
					%endif
				%endif
				%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
					;// Windows fastcall uses one index for either
					;// int or float params for purpose of preloading regs
					%assign %$__nx_intargs 1 + %$__nx_intargs
				%endif
				%assign %$__nx_floatargs 1 + %$__nx_floatargs
				%undef %$arg_cur
			%endif
			%if %%__argtostack != 0
				;// assert: no available registers
				%if %$__nx_argv_mode_param_isfloat == 0
					%ifnum %1
						%if __NASMX_ABI_BITS__ > 32
							mov __AX, %{1}
							mov size_t [__SP + %$args], __AX
							%if %$__reg_ax_saved != 0
								mov __AX, size_t [__SP - __NASMX_ABI_BITS__ / 8]
							%endif
						%else
							mov size_t [__SP + %$args], %{1}
						%endif
					%elifstr %1
						jmp %%endstr_%$args
						%%str_%$args: declare(NASMX_TCHAR) NASMX_TEXT(%1), 0
						%%endstr_%$args:
						lea __AX,[rel %%str_%$args]
						mov [__SP + %$args], __AX
						%if %$__reg_ax_saved != 0
							mov __AX, size_t [__SP - __NASMX_ABI_BITS__ / 8]
						%endif
					%else
						%if %$__nx_argv_mode_indirect > 0
							%if %$__nx_argv_mode_castsize < 4
								%xdefine %$arg_cur AX
							%elif %$__nx_argv_mode_castsize < 8
								%xdefine %$arg_cur EAX
							%else
								%xdefine %$arg_cur RAX
							%endif
							mov %$arg_cur, %{1}
							mov [__SP + %$args], __AX
							%undef %$arg_cur
							%if %$__reg_ax_saved != 0
								mov __AX, size_t [__SP - __NASMX_ABI_BITS__ / 8]
							%endif
						%elif %$__nx_argv_mode_bp > 0
							mov  __AX, __BP
							%if %$__nx_argv_mode_sign == __NX_ARGV_MODE_SIGN_ADD__
								add __AX, %$__nx_argv_mode_bp_offset
							%elif %$__nx_argv_mode_sign == __NX_ARGV_MODE_SIGN_SUB__
								sub __AX, %$__nx_argv_mode_bp_offset
							%else
								%fatal Unknown addressing mode for %{1}
							%endif
							mov [__SP + %$args], __AX
							%if %$__reg_ax_saved != 0
								mov __AX, size_t [__SP - __NASMX_ABI_BITS__ / 8]
							%endif
						%else
							mov size_t [__SP + %$args], %{1}
						%endif
					%endif
				%else
					;// assert: processing float param
					%if %$__nx_argv_mode_indirect > 0
						%if %$__nx_argv_mode_castsize > %$__nx_argv_mode_param_size
							%warning potential loss of precision during conversion of double to float for %[%1]
						%endif
						fld __nx_error_token_size_%[%$__nx_argv_mode_castsize] %1
						fstp __nx_error_token_size_%[%$__nx_argv_mode_param_size] [__SP + %$args]
					%elif %$__nx_argv_mode_bp > 0
						fld __nx_error_token_size_%[%$__nx_argv_mode_param_size] [%1]
						fstp __nx_error_token_size_%[%$__nx_argv_mode_param_size] [__SP + %$args]
					%else
						%if %$__nx_argv_mode_fp_isnum != 0
							;// assert: arg is floating point constant
							%if %$__nx_argv_mode_param_size == 4
								;// assert: callee expecting float type
								mov  eax, %$__nx_argv_mode_fp_num
								mov  size_t [__SP + %$args], __AX
							%else
								;// assert: callee expecting double type
								%if __NASMX_ABI_BITS__ > 32
									mov  __AX, %1
									mov  qword [__SP + %$args], __AX
									%if %$__reg_ax_saved != 0
										mov __AX, size_t [__SP - __NASMX_ABI_BITS__ / 8]
									%endif
								%else
									%assign %%__tmp (%$__nx_argv_mode_fp_num & 0x00000000FFFFFFFF)
									mov dword [__SP + %$args], %%__tmp
									%assign %%__tmp ((%$__nx_argv_mode_fp_num >> 32) & 0x00000000FFFFFFFF)
									mov dword [__SP+%$args+4], %%__tmp
								%endif
							%endif
						%else
							mov __nx_error_token_size_%[%$__nx_argv_mode_param_size] [__SP + %$args], %1
						%endif
					%endif
				%endif
				%if __NASMX_ABI_BITS__ > 32
					;// assert: we must increase stack offset by size_t regardless
					;// of whether we're storing a float or a double
					%assign %$args %$args + sizeof(size_t)
				%else
					%if %$__nx_argv_mode_param_size <= sizeof(size_t)
						%assign %$args %$args + sizeof(size_t)
					%else
						%assign %$args %$args + %$__nx_argv_mode_param_size
					%endif
				%endif
			%endif
		%endrep
		;// stack is set up, call the proc
		call	%$__nx_proc
		%if %$__nx_bytecount > 0
			%if %$__nx_callstack_adjust == 0
				%if %$__nx_retpopsargs == 0
					%if %$__nx_invoke_callstack_adjust > 0
						add	__SP, %$__nx_invoke_callstack_adjust
					%endif
				%elif %$__align > 0
					add	__SP, %$__align
				%endif
			%endif
		%endif
	%else
		;// arg types follow cconv,bytecount when defined
		%if %$__nx_argrotate > 0
			%assign %$__param_type_ctr 2    
		%else
			%assign %$__param_type_ctr %0+2
		%endif

		%rep %%__repcnt
			%rotate %$__nx_argrotate

			;// set up internal vars used to determine if argv address mode used
			%assign %$__param_type_ctr %$__param_type_ctr + %$__nx_argrotate
			nx_analyze_argv_mode %{1}, %$__param_type_ctr

			%if %$__nx_argv_mode_param_isfloat == 0
				%ifstr	%1
					jmp	%%endstr_%$args
					%%str_%$args: declare(NASMX_TCHAR) NASMX_TEXT(%{1}), 0
					%%endstr_%$args:
					push size_t %%str_%$args
				%elifnum %1
					push size_t %1
				%elif %$__nx_argv_mode_indirect > 0
					push size_t %1
				%elif %$__nx_argv_mode_bp > 0
					%if %$__reg_ax_saved != 0
						mov size_t [__SP - __NASMX_ABI_BITS__ / 8 * 2], __AX
					%endif
					mov  __AX, __BP
					%if %$__nx_argv_mode_sign == __NX_ARGV_MODE_SIGN_ADD__
						add __AX, %$__nx_argv_mode_bp_offset
					%elif %$__nx_argv_mode_sign == __NX_ARGV_MODE_SIGN_SUB__
						sub __AX, %$__nx_argv_mode_bp_offset
					%else
						%fatal Unknown addressing mode for %{1}
					%endif
					push __AX
					%if %$__reg_ax_saved != 0
						mov __AX, size_t [__SP - __NASMX_ABI_BITS__ / 8]
					%endif
				%else
					push size_t %1
				%endif
				%assign %$args %$args + __BITS__ / 8
			%else
				;// process float param
				%if %$__nx_argv_mode_param_size < sizeof(size_t)
					;// if passing a float in 64-bit mode
					sub __SP, sizeof(size_t)
					%assign %$args %$args + sizeof(size_t)
				%else
					;// may be passing double in 32-bit mode
					sub  __SP, %$__nx_argv_mode_param_size
					%assign %$args %$args + %$__nx_argv_mode_param_size
				%endif
				%if %$__nx_argv_mode_indirect > 0
					%if %$__nx_argv_mode_castsize > %$__nx_argv_mode_param_size
						%warning potential loss of precision during conversion of double to float for %[%1]
					%endif
					fld __nx_error_token_size_%[%$__nx_argv_mode_castsize] %1
					fstp __nx_error_token_size_%[%$__nx_argv_mode_param_size] [__SP]
				%elif %$__nx_argv_mode_bp > 0
					fld __nx_error_token_size_%[%$__nx_argv_mode_param_size] [%1]
					fstp __nx_error_token_size_%[%$__nx_argv_mode_param_size] [__SP]
				%else
					%if %$__nx_argv_mode_fp_isnum != 0
						%if %$__nx_argv_mode_param_size == 4
							;// assert: callee expecting float type
							mov dword [__SP], %$__nx_argv_mode_fp_num
						%else
							;// assert: callee expecting double type
							%assign %%__tmp (%$__nx_argv_mode_fp_num & 0x00000000FFFFFFFF)
							mov dword [__SP], %%__tmp
							%assign %%__tmp ((%$__nx_argv_mode_fp_num >> 32) & 0x00000000FFFFFFFF)
							mov dword [__SP+4], %%__tmp
						%endif
					%else
						mov [__SP], %1
					%endif
				%endif
			%endif
		%endrep
		call %$__nx_proc
		%if %$args > 0
			%if %$__nx_retpopsargs == 0
				add	__SP, %$args
			%endif
		%endif
	%endif

	;// cleanup global arg token defs
	%assign %%__ctr 1
	%rep 16
		%ifdef __nx_token_%[%%__ctr]
			%undef __nx_token_%[%%__ctr]
		%endif
		%assign %%__ctr %%__ctr + 1
	%endrep

	;// restore context stack
	%pop
%endmacro


;//////////////////////////////////////////////////////////////
;// MACRO PROC
;//
;// usage:
;//    PROC [CALLCONV,] funcname [ arg, arg, ...]
;//
;// examples:
;//    Using default calling convention:
;//       proc funcname, arg1, arg2
;//    Specifying calling convention:
;//       proc cdecl, fprintf
;//
;// notes:
;//   The calling convention, if specified, must match either
;//   the prototype or import specification.
;//   Also remember that, when invoked during a fastcall, the
;//   register parameters are not automatically spilled, only
;//   the space assigned on the stack is allocated.
;//   This allows the user to determine whether or not to use
;//   the spill area if needed.
;//
%imacro PROC 1-100.nolist
	%ifdef NASMX_ENDPROC
		%fatal 'missing endproc directive.'
	%endif
	%push __NX_CTX_PROC__
	%assign %$__nx_locnt 0             ;// init locals offset
	%assign %$__nx_intargs 0           ;// init int args counter
	%assign %$__nx_floatargs 0         ;// init float args counter
	%assign %$__nx_bytecount 0         ;// init total args byte count
	%assign %$__nx_protobytecount -1   ;// >= 0 if defined
	%ifndef __NASMX_DECLSPEC_CALLCONV_%[%1]__
		;// check for prototyped func
		%ifdef __nxsig@@%[%1]
			nx_parse_tokens __nxsig@@%[%1]
			%assign %$__nx_callconv __nx_token_1
			%assign %$__nx_protobytecount __nx_token_2
		%else
			%assign %$__nx_callconv __NASMX_DECLSPEC_CALLCONV_DEFAULT__
		%endif
		%define %$__nx_proc %1
		%assign %$__nx_repcnt %0 - 1
	%else
		%if %0 < 2
			%fatal 'usage: PROC [CALLCONV, ] FUNCNAME [,ARG1,ARG2,...]'
		%endif
		%assign %$__nx_callconv __NASMX_DECLSPEC_CALLCONV_%[%1]__
		%define %$__nx_proc %2
		%assign %$__nx_repcnt %0-2
		;// check for prototyped func
		%ifdef __nxsig@@%[%2]
			nx_parse_tokens __nxsig@@%[%2]
			%if %$__nx_callconv != __nx_token_1
				%fatal calling convention mismatch for %$__nx_proc
			%endif
			%assign %$__nx_protobytecount __nx_token_2
		%endif
	%endif

	;// init proc args counter and get callconv enum
	%assign %$__nx_argv_count %$__nx_repcnt
	%assign %$__nx_cc_enum nx_declspec_cc_enum(%[%$__nx_callconv])
	
	;// v1.0rc2 - we must always calculate a true bytecount such that
	;// the implementation of main(), or imported functions that are
	;// defined with a 0 bytecount, are defined properly
	%ifdef __nx_proto_param_list
		%undef __nx_proto_param_list
	%endif
	%rep %0-%$__nx_repcnt
		%rotate 1
	%endrep
	;// The signature must be defined in full before use because once the
	;// procedure has been defined we are not able to easily redefine it.
	;// Due to dependency on the X64_SPILL_OFFSET we cannot simply use one
	;// rep loop to generate equate offsets
	;// Thus the rep loop is required twice:
	;//     First, to build the parameter type list and x64 spill area size
	;//     Then, later on, to build the parameter offset equates.
	%rep %$__nx_repcnt
		nx_strtok %1, ' '
		;// assert: calculate bytecount in this loop to account
		;// for param types double/int128 rather than the simple logic of
		;// %assign %$__nx_bytecount %$__nx_repcnt * sizeof(size_t)
		;// Also build the parameter type list here in case the procedure
		;// has not been prototyped or imported.
		%xdefine __nx_proto_argtype %$__nx_token %+ __nx_type
		%assign %%__param_type __nx_proto_argtype
		%assign %%__param_size (%%__param_type & 0x7F)
		%if %%__param_size < sizeof(size_t)
			%assign %$__nx_bytecount %$__nx_bytecount + sizeof(size_t)
		%elif %%__param_size <= __NASMX_ABI_BITS__ / 4
			%assign %$__nx_bytecount %$__nx_bytecount + %%__param_size
		%else
			%error parameter exceeds allowable size: %1
		%endif
		%ifndef __nx_proto_param_list
			%defstr __nx_proto_param_list __nx_proto_argtype
		%else
			%defstr __nx_proto_argstr __nx_proto_argtype
			%strcat __nx_proto_param_list __nx_proto_param_list,',',__nx_proto_argstr
			%undef __nx_proto_argstr
		%endif
		%undef __nx_proto_argtype

		;// NASMX 1.4 - New behavior: auto-spill register args if not disabled
		%if %$__nx_cc_enum == __NASMX_DECLSPEC_CC_ENUM_FASTCALL__
			%ifndef DISABLE_PROC_FASTCALL_STACK_PRELOAD
				%assign %$__reg_size __NASMX_ABI_BITS__ / 8
				%assign %%__isfloat is_typeof_float(%[%$__nx_token])
				%if %%__isfloat == 0
					%if %$__nx_intargs < __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__
						%substr %%__regstr __NASMX_DECLSPEC_FASTCALL_REGINTARGS_%[%$__reg_size]__ (%$__nx_intargs * 3 + 1), 3
						%deftok %$arg_cur %%__regstr
						__nx_stack_push NASMX_SPILL_REG_NAME, %[%$arg_cur]
						__nx_stack_push NASMX_SPILL_REG_TYPE, %[%$__nx_token]
						%undef %%__regstr
					%endif
					%assign %$__nx_intargs %$__nx_intargs + 1
					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						;// Windows fastcall uses one index for either
						;// int or float params for purpose of preloading regs
						%assign %$__nx_floatargs %$__nx_floatargs + 1
					%endif
				%else
					%if %$__nx_floatargs < __NASMX_DECLSPEC_FASTCALL_MAXFLOATREGS__
						%substr %%__regstr __NASMX_DECLSPEC_FASTCALL_REGFLOATARGS_%[%$__reg_size]__ (%$__nx_floatargs * 4 + 1), 4
						%deftok %$arg_cur %%__regstr
						__nx_stack_push NASMX_SPILL_REG_NAME, %[%$arg_cur]
						__nx_stack_push NASMX_SPILL_REG_TYPE, %[%$__nx_token]
						%undef %%__regstr
					%endif
					%assign %$__nx_floatargs %$__nx_floatargs + 1
					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						;// Windows fastcall uses one index for either
						;// int or float params for purpose of preloading regs
						%assign %$__nx_intargs 1 + %$__nx_intargs
					%endif
				%endif
			%endif
		%endif

		%rotate 1
	%endrep

	%ifndef __nxsig@@%[%$__nx_proc]
		;// assert: we must generate an appropriate label for the function call
		;// here in order for the parameters to be equated properly
		nx_callconv_decorate %$__nx_callconv,%$__nx_proc,%$__nx_bytecount
		%ifdef __nx_proto_param_list
			%deftok __nx_proto_params __nx_proto_param_list
			%xdefine __nxsig@@%[%$__nxtok_decorated_name] %[%$__nx_callconv],%[%$__nx_bytecount],__nx_proto_params
		%else
			%xdefine __nxsig@@%[%$__nxtok_decorated_name] %[%$__nx_callconv],%[%$__nx_bytecount]
		%endif
		%ifnidn %$__nx_proc,%$__nxtok_decorated_name
			%xdefine %[%$__nx_proc] %[%$__nxtok_decorated_name]
		%endif
	%endif

	%ifdef __nxsig_defined_%[%$__nx_proc]
		%fatal procedure %[%$__nx_proc] already defined
	%else
		%xdefine __nxsig_defined_%[%$__nx_proc]
	%endif

	;// emit the procedure entry point
	%[%$__nx_proc]:

	;// The following define can/should be used by the user to properly
	;// return from a function ( ie: jmp NASMX_ENDPROC ) or via use of
	;// the RETURN macro
	%xdefine NASMX_ENDPROC __nx_endproc@@%[%$__nx_proc]

	%if %$__nx_cc_enum != __NASMX_DECLSPEC_CC_ENUM_NAKED__
		%assign %$__nx_intargs 0
		%assign %$__nx_floatargs 0
		%assign %$__nx_argv __NASMX_ABI_BITS__ / 4

		;// assert: calc byte count for sig check and argv() offsets
		;// we must reverse arg push logic to get correct results
		%assign %$__nx_bytecount 0
		%assign %$__cc_argrotate nx_declspec_cc_argrotate(%[%$__nx_callconv])
		%if %$__cc_argrotate != 0
			%assign %$__nx_argrotate -1
			%rotate -1
		%else
			%assign %$__nx_argrotate 1
			%rep %0-%$__nx_repcnt
				%rotate 1
			%endrep
		%endif

		%rep %$__nx_repcnt
			;// obtain param type and size and validate against current ABI
			nx_strtok %1, ' '
			%assign %%__isfloat is_typeof_float(%[%$__nx_token])
			%assign %%__param_size sizeof(%[%$__nx_token]) ; _size
			nx_strtok 0, ' '
			;// only allow exceeding of size_t for type double
			;// in 32-bit mode and 128-bit params in 64-bit mode
			%if %%__param_size > (sizeof(size_t) * 2)
			    %fatal %[%$__nx_token] invalid parameter size: %%__param_size
			%endif
			%if %%__param_size < sizeof(size_t)
				%assign %%__param_size sizeof(size_t)
			%endif
			%assign %$__nx_bytecount %$__nx_bytecount + %%__param_size

			%if __NASMX_ABI_BITS__ > 32
				%if %$__nx_cc_enum == __NASMX_DECLSPEC_CC_ENUM_FASTCALL__
					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						;// assert: Windows 64-bit register spill area
						;// located above return address, thus bias
						;// not affected
						%assign %$__nx_intargs 1 + %$__nx_intargs
						%if %%__isfloat == 0
							%if %%__param_size > sizeof(size_t)
								%if %$__nx_intargs == __NASMX_DECLSPEC_FASTCALL_MAXINTREGS__
									%error in procedure %$__nx_proc %$__nx_token exceeds available registers
								%endif
							%endif
						%endif
						.%[%$__nx_token] EQU %[%$__nx_argv]
						%assign %$__nx_argv %%__param_size + %$__nx_argv
					%else
						;// assert: Linux 64-bit register spill area located
						;// below frame pointer, defer equating until later.
						__nx_stack_push PROLOGUE_X64_PARAM_NAME, %[%$__nx_token]
					%endif
				%else
					.%[%$__nx_token] EQU %[%$__nx_argv]
					%assign %$__nx_argv %$__nx_argv + %%__param_size
				%endif
			%else
				.%[%$__nx_token] EQU %[%$__nx_argv]
				%assign %$__nx_argv %$__nx_argv + %%__param_size
			%endif
			%rotate %$__nx_argrotate
		%endrep

		%if %$__nx_protobytecount > 0
			;// assert: we can only validate against prototypes that
			;// have a byte count since vararg functions can only be
			;// defined with zero (0) bytecount
			%if %$__nx_bytecount != %$__nx_protobytecount
				;// In the program entry main procedure the user may, or may not,
				;// be using command line or environment params.
				%ifnidni %$__nx_proc, main
					;// unfortunately we must check callconv for cdecl on win32
					;// and fastcall on win64 as currently the import files do
					;// not contain bytecounts to verify against.
					;// TODO: When import files are updated in the future we can
					;// revisit this code.
					%ifidni __OUTPUT_FORMAT__,win32
						%if %$__nx_cc_enum != __NASMX_DECLSPEC_CC_ENUM_CDECL__
							%warning prototype arg mismatch for %$__nx_proc
						%endif
					%elifidni __OUTPUT_FORMAT__,win64
						%if %$__nx_cc_enum != __NASMX_DECLSPEC_CC_ENUM_FASTCALL__
							%warning prototype arg mismatch for %$__nx_proc
						%endif
					%else
						%warning prototype arg mismatch for %$__nx_proc
					%endif
				%endif
			%endif
		%endif

		%ifidni %$__nx_proc, main
			;// assert: always push __BP to get an aligned stack
			%define __NX_PROLOGUE_PRESENT__
			push __BP
			mov  __BP, __SP

			;// assert: ensure we start out with an aligned stack
			%assign %%__nx_align ((__NASMX_ABI_BITS__ / 4 ) - 1)
			mov   __AX, __SP
			and   __AX, %%__nx_align
			jz    .nx_main_aligned
			sub   __SP, (__NASMX_ABI_BITS__ / 4 )
			%if __NASMX_ABI_BITS__ > 32
				and spl,BYTE 0xF0
			%else
				and   __SP, -8
			%endif
			.nx_main_aligned:
		%endif
	%endif
%endmacro


;//////////////////////////////////////////////////////////////
;// MACRO USES
;//
;// usage:
;//    USES reg [,reg ,reg, ...]
;//
;// examples:
;//    USES rbx, r15
;//
;// notes:
;//    This macro can only be used within the proc prologue
;//    Fatals are used rather than errors as this macro is
;//    extremely critical to proper function definition and
;//    stack alignment if used.
;//
%imacro USES 1-16.nolist
	%ifndef NASMX_ENDPROC
		%fatal 'missing proc directive.'
	%endif
	%ifnctx __NX_CTX_PROC__
		%fatal 'current context unknown.'
	%endif
	%ifdef __NX_LOCALS_PRESENT__
		%fatal 'uses directive must come before locals directive.'
	%endif
	%ifdef __NX_USES_PRESENT__
		%fatal 'uses directive previously set for this procedure.'
	%endif
	%define __NX_USES_PRESENT__

	%assign %%__sys_size __NASMX_ABI_BITS__
	%assign %%__size __NASMX_ABI_BITS__ / 8
	%assign %$__nx_uses_adjust %0 * %%__size
	%rep %0
		%ifndef %[%1]_size
			%fatal unknown register: %1
		%endif
		%assign %%__reg_size %[%1]_size
		%if %%__reg_size < %%__size
			%fatal extended version of register %1 required for %%__sys_size bit mode
		%elif %%__reg_size > %%__size
			%fatal %1 not available in %%__sys_size bit mode
		%endif
		__nx_stack_push NASMX_USES_REGS, %[%1]
		%rotate 1
	%endrep

	;// during endproc stack adjustment to include difference
	;// between locnt and uses_adjust
	%xdefine __NX_PROLOGUE_USES_ADJUST__ %[%$__nx_uses_adjust]

%endmacro


;//////////////////////////////////////////////////////////////
;// MACRO LOCALS
;//
;// usage:
;//    locals [none]
;// where
;//    none - allows us to avoid using stackframe if user
;//           writing a small leaf function or will handle
;//           function prologue separately.  Also indicates
;//           that endlocals directive not required.
;//
;// notes:
;//    This macro can only be used within the proc prologue
;//    and must precede any assembly code. Invoke checks to
;//    verify that this macro was called to ensure that the
;//    prologue was initialized properly.
;//
%imacro LOCALS 0-1.nolist
	%ifndef NASMX_ENDPROC
		%error 'missing proc directive.'
	%endif
	%ifndef __NX_LOCALS_PRESENT__
		%define __NX_LOCALS_PRESENT__
	%endif
	%if %0 == 1
		%ifidni %1,none
			%define __NX_LOCALS_NONE__
		%else
			%warning unknown locals directive: %1
		%endif
	%endif

	%ifndef __NX_PROLOGUE_USES_ADJUST__
		%xdefine __NX_PROLOGUE_USES_ADJUST__ 0
	%endif

	%ifndef __NX_PROLOGUE_PRESENT__
		%define __NX_PROLOGUE_PRESENT__
		push __BP

		;// if there are no locals, no parameters, and no x64 prologue requirements
		;// then don't emit mov __SP, __BP
		%ifnidni %$__nx_proc, main
			%ifdef __NX_STACK_IDX_PROLOGUE_X64_PARAM_NAME
				mov  __BP, __SP
			%elifndef __NX_LOCALS_NONE__
				mov  __BP, __SP
			%elif %$__nx_argv_count > 0
				mov  __BP, __SP
			%endif
		%endif
	%endif

	;// calculate this once
	%assign %$__reg_size __NASMX_ABI_BITS__ / 8

	%ifdef __NX_USES_PRESENT__
		%assign %%__nx_reg 1
		%assign %$__nx_uses_count __NX_STACK_IDX_NASMX_USES_REGS
		%rep %$__nx_uses_count
			push %[__NX_STACK_NASMX_USES_REGS_ %+ %%__nx_reg]
			%assign %$__nx_locnt %$__nx_locnt + %$__reg_size
			%assign %%__nx_reg %%__nx_reg + 1
		%endrep
	%endif

	;// at this point we can create the linux spill area if necessary
	%ifdef __NX_STACK_IDX_PROLOGUE_X64_PARAM_NAME
		%assign %%__idx __NX_STACK_IDX_PROLOGUE_X64_PARAM_NAME
		%assign %%__params %%__idx
		%rep %%__params
			%assign %$__nx_locnt %$__reg_size + %$__nx_locnt
			.%[__NX_STACK_PROLOGUE_X64_PARAM_NAME_ %+ %%__idx] EQU %[%$__nx_locnt]
			%assign %%__idx %%__idx - 1
			__nx_stack_pop PROLOGUE_X64_PARAM_NAME
		%endrep
		%assign %$__nx_x64_loc %$__nx_locnt
	%endif

	%ifdef __NX_LOCALS_NONE__
		%ifdef __NX_PROLOGUE_CALLSTACK_ADJUST__
			%assign %$__nx_locnt %$__nx_locnt + __NX_PROLOGUE_CALLSTACK_ADJUST__
		%endif
		%if %$__nx_locnt > 0
			;// assert: the following block of code added for NASMX 1.0rc2
			;// to ensure that stack is aligned properly for functions
			;// which do not define any locals, save odd count registers,
			;// or linux x64 procs with unaligned spill area
			%assign %%__align __NASMX_ABI_BITS__ / 4
			%assign %%__off (((%$__nx_locnt + %%__align) / %%__align) * %%__align)
			%assign %%__tmp (%$__nx_locnt + %%__align)
			%if (%%__off != %%__tmp)
				%assign %$__nx_locnt %$__nx_locnt + %$__reg_size
			%endif
			%assign %%__alloca %$__nx_locnt - __NX_PROLOGUE_USES_ADJUST__
			%if %%__alloca > 0
				sub  __SP, %%__alloca
			%endif
		%endif

		;// auto-spill registers, if any
		%ifdef __NX_STACK_IDX_NASMX_SPILL_REG_NAME
			%assign %%__ofst %$__reg_size * 2
			%assign %%ctr 1
			%assign %%__repcnt __NX_STACK_IDX_NASMX_SPILL_REG_NAME
			%rep %%__repcnt
				%assign %%__isfloat is_typeof_float(%[__NX_STACK_NASMX_SPILL_REG_TYPE_ %+ %%ctr])
				%if %%__isfloat == 0
					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						mov size_t [__BP + %%__ofst], %[__NX_STACK_NASMX_SPILL_REG_NAME_ %+ %%ctr]
						%assign %%__ofst %%__ofst + %$__reg_size
					%else
						mov size_t [__BP - %$__nx_x64_loc], %[__NX_STACK_NASMX_SPILL_REG_NAME_ %+ %%ctr]
						%assign %$__nx_x64_loc %$__nx_x64_loc - %$__reg_size
					%endif
				%else
					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						movq size_t [__BP + %%__ofst], %[__NX_STACK_NASMX_SPILL_REG_NAME_ %+ %%ctr]
						%assign %%__ofst %%__ofst + %$__reg_size
					%else
						movq size_t [__BP - %$__nx_x64_loc], %[__NX_STACK_NASMX_SPILL_REG_NAME_ %+ %%ctr]
						%assign %$__nx_x64_loc %$__nx_x64_loc - %$__reg_size
					%endif				
				%endif
				%assign %%ctr %%ctr + 1
			%endrep
			%rep %%__repcnt
				__nx_stack_pop NASMX_SPILL_REG_NAME
				__nx_stack_pop NASMX_SPILL_REG_TYPE
			%endrep
		%endif
	%endif
%endmacro


%imacro LOCAL 2-3.nolist 1
	%ifndef __NX_LOCALS_PRESENT__
		%error 'missing locals directive.'
	%endif
	%ifdef __NX_LOCALS_NONE__
		%error 'conflicts with directive: locals none'
	%endif
	%ifndef %[%2]_size
		%error %1 unknown size: %2
	%endif
	%assign %%__size %[%2]_size
	%assign %$__nx_locnt %$__nx_locnt + (%%__size * %3)

	;// ensure natural alignment of stack local variables
	;// TODO: A nice, but not trivial, optimization to reduce
	;// stack usage even further would be to reorganize equate
	;// offsets of local variables similar to a real compiler.
	%if %%__size <= 4
		%assign %%__align 4
	%elif %%__size <= 8
		%assign %%__align 8
	%elif %%__size > 16
		%assign %%__align __NASMX_ABI_BITS__ / 8
	%else
		%assign %%__align __NASMX_ABI_BITS__ / 4
	%endif
	%assign %%__off (((%$__nx_locnt + %%__align) / %%__align) * %%__align)
	%assign %%__tmp (%$__nx_locnt + %%__align)
	%if (%%__off != %%__tmp)
		%assign %$__nx_locnt %%__off
	%endif
	.%[%1] EQU %$__nx_locnt
%endmacro


%imacro ENDLOCALS 0.nolist
	%ifndef __NX_LOCALS_PRESENT__
		%error 'missing locals directive.'
	%endif
	%ifndef __NX_LOCALS_NONE__
		%ifdef __NX_PROLOGUE_CALLSTACK_ADJUST__
			%assign %$__nx_locnt %$__nx_locnt + __NX_PROLOGUE_CALLSTACK_ADJUST__
		%endif
		%if %$__nx_locnt > 0
			;// keep stack aligned
			%assign %%__align __NASMX_ABI_BITS__ / 4
			%assign %%__off (((%$__nx_locnt + %%__align) / %%__align) * %%__align)
			%assign %%__tmp (%$__nx_locnt + %%__align)
			%if (%%__off != %%__tmp)
				%assign %$__nx_locnt %%__off
			%endif
			%assign %%__alloca %$__nx_locnt - __NX_PROLOGUE_USES_ADJUST__
			%if %%__alloca > 0
				sub  __SP, %%__alloca
			%endif
		%endif

		;// auto-spill registers, if any
		%ifdef __NX_STACK_IDX_NASMX_SPILL_REG_NAME
			%assign %%__ofst %$__reg_size * 2
			%assign %%ctr 1
			%assign %%__repcnt __NX_STACK_IDX_NASMX_SPILL_REG_NAME
			%rep %%__repcnt
				%assign %%__isfloat is_typeof_float(%[__NX_STACK_NASMX_SPILL_REG_TYPE_ %+ %%ctr])
				%if %%__isfloat == 0
					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						mov size_t [__BP + %%__ofst], %[__NX_STACK_NASMX_SPILL_REG_NAME_ %+ %%ctr]
						%assign %%__ofst %%__ofst + %$__reg_size
					%else
						mov size_t [__BP - %$__nx_x64_loc], %[__NX_STACK_NASMX_SPILL_REG_NAME_ %+ %%ctr]
						%assign %$__nx_x64_loc %$__nx_x64_loc - %$__reg_size
					%endif
				%else
					%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ == __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
						movsd size_t [__BP + %%__ofst], %[__NX_STACK_NASMX_SPILL_REG_NAME_ %+ %%ctr]
						%assign %%__ofst %%__ofst + %$__reg_size
					%else
						movsd size_t [__BP - %$__nx_x64_loc], %[__NX_STACK_NASMX_SPILL_REG_NAME_ %+ %%ctr]
						%assign %$__nx_x64_loc %$__nx_x64_loc - %$__reg_size
					%endif
				%endif
				%assign %%ctr %%ctr + 1
			%endrep
			%rep %%__repcnt
				__nx_stack_pop NASMX_SPILL_REG_NAME
				__nx_stack_pop NASMX_SPILL_REG_TYPE
			%endrep
		%endif
	%endif
%endmacro

;// the following provide accessor macros to the procedure
;// parameter arguments and local variables
%if __NASMX_ABI_BITS__ > 32
	%if __NASMX_DECLSPEC_SYSTYPE_DEFAULT__ != __NASMX_DECLSPEC_SYSTYPE_WINDOWS__
		;// Linux x64 argv offsets defined identically to var offsets
		%idefine argv(v) rbp - v
	%else
		%idefine argv(v) rbp + v
	%endif
	%idefine  var(v) rbp - v
%else
	%idefine argv(v) ebp + v
	%idefine  var(v) ebp - v
%endif

%idefine OFFSET

%imacro RETURN 0-1.nolist
	%if %0 > 0
		%ifnum %1
			%if %1 == -1
				or __AX, %1
			%elif %1 == 0
				xor __AX, __AX
			%else
				mov __AX, %1
			%endif
		%else
			%ifnidni %1, __AX
				mov __AX, %[%1]
			%endif
		%endif
	%endif
	jmp  NASMX_ENDPROC
%endmacro

%imacro LEAVE 0.nolist
	%ifndef __NX_LEAVE_PRESENT__
		%define __NX_LEAVE_PRESENT__
		%ifdef NASMX_ENDPROC
			;// reset __SP to end of saved registers, if any
			%ifdef __NX_LOCALS_PRESENT__
				%assign %%__alloc %$__nx_locnt - __NX_PROLOGUE_USES_ADJUST__
				%if %%__alloc > 0
					add  __SP, %%__alloc
				%endif
			%endif
			;// restore any non-volatile registers
			%ifdef __NX_USES_PRESENT__
				%assign %%__nx_reg __NX_STACK_IDX_NASMX_USES_REGS
				%assign %$__nx_uses_count __NX_STACK_IDX_NASMX_USES_REGS
				%rep %$__nx_uses_count
					pop __NX_STACK_NASMX_USES_REGS_%[%%__nx_reg]
					__nx_stack_pop NASMX_USES_REGS
					%assign %%__nx_reg %%__nx_reg - 1
				%endrep
			%endif
		%endif
		%ifdef __NX_PROLOGUE_PRESENT__
			%ifidn %[%$__nx_proc],main
				mov __SP, __BP
			%endif
			pop __BP
		%endif
	%endif
%endmacro

%imacro RET 0-1.nolist
	%ifdef NASMX_ENDPROC
		%ifndef __NX_LEAVE_PRESENT__
			leave
		%endif
		%define __NX_RETURN_PRESENT__
	%endif

	%if %0 == 1
		%ifnum %1
			%if %1 > 0
				ret %1
			%else
				ret
			%endif
		%elifid %1
			%if %[%1] > 0
				ret %[%1]
			%else
				ret
			%endif
		%else
			%warning 'invalid operand supplied to ret opcode'
			ret
		%endif
	%else
		ret
	%endif
%endmacro

%imacro ENDPROC 0.nolist
	%ifndef NASMX_ENDPROC
		%fatal 'missing proc directive.'
	%endif
	;// NASMX v1.3.1
	;// added check to ensure stack was set up
	;// properly in case invoke macro not used.
	%ifndef __NX_LOCALS_PRESENT__
		%fatal 'missing locals directive.'
	%endif

	;// provide a proc end jmp label
	%[NASMX_ENDPROC]:

	;// assert: we can not be certain at what context level we are at,
	;// thus we pop all contexts until we get to __NX_CTX_PROC__
	%rep 32
		;// Bugfix:
		;// Avoid problem with exitrep not exiting
		;// the loop immediately.
		%ifctx __NX_CTX_PROC__
			%exitrep
		%else
			%pop
		%endif
	%endrep

	%ifndef __NX_RETURN_PRESENT__
		%assign %%__cc_retpopsargs nx_declspec_cc_retpopsargs(%$__nx_callconv)
		%if %%__cc_retpopsargs == 0
			ret
		%else
			;// x64 retpopcnt may be different than bytecount
			%assign %$__nx_retpopcnt (%$__nx_argv - (__NASMX_ABI_BITS__ / 4))
			%if %$__nx_retpopcnt > 0
				ret %[%$__nx_retpopcnt]
			%else
				ret
			%endif
		%endif
	%endif
	%pop
	%undef NASMX_ENDPROC
	%ifdef __NX_LEAVE_PRESENT__
		%undef __NX_LEAVE_PRESENT__
	%endif
	%ifdef __NX_RETURN_PRESENT__
		%undef __NX_RETURN_PRESENT__
	%endif
	%ifdef __NX_USES_PRESENT__
		%undef __NX_USES_PRESENT__
	%endif
	%ifdef __NX_LOCALS_PRESENT__
		%undef __NX_LOCALS_PRESENT__
	%endif
	%ifdef __NX_LOCALS_NONE__
		%undef __NX_LOCALS_NONE__
	%endif
	%ifdef __NX_PROLOGUE_PRESENT__
		%undef __NX_PROLOGUE_PRESENT__
	%endif
	%ifdef __NX_PROLOGUE_USES_ADJUST__
		%undef __NX_PROLOGUE_USES_ADJUST__
	%endif
%endmacro


%imacro RJMP 2.nolist
; This macro preforms the opposite conditional jump
; than what the value suggests, it's used internally
; by other macros
	%ifidni %1, ==
		jne %2
	%elifidni %1, >
		jle %2
	%elifidni %1, <
		jge %2
	%elifidni %1, >=
		jl %2
	%elifidni %1, <=
		jg %2
	%elifidni %1, !=
		je %2
	%elifidni %1, !>
		jg %2
	%elifidni %1, !<
		jl %2
	%elifidni %1, CARRY
		jnc %2
	%elifidni %1, BELOW
		jnb %2
	%elifidni %1, ABOVE
		jna %2
	%elifidni %1, PARITY
		jnp %2
	%elifidni %1, SIGNED
		jns %2
	%elifidni %1, OVERFLOW
		jno %2
	%elifidni %1, !CARRY
		jc %2
	%elifidni %1, !BELOW
		jb %2
	%elifidni %1, !ABOVE
		ja %2
	%elifidni %1, !PARITY
		jp %2
	%elifidni %1, !SIGNED
		js %2
	%elifidni %1, !OVERFLOW
		jo %2
	%endif
%endmacro


%imacro SJMP 2.nolist
	%ifidni %1, ==
		je %2
	%elifidni %1, >
		jg %2
	%elifidni %1, <
		jl %2
	%elifidni %1, >=
		jge %2
	%elifidni %1, <=
		jle %2
	%elifidni %1, !=
		jne %2
	%elifidni %1, !>
		jng %2
	%elifidni %1, !<
		jnl %2
	%elifidni %1, CARRY
		jc %2
	%elifidni %1, BELOW
		jb %2
	%elifidni %1, ABOVE
		ja %2
	%elifidni %1, PARITY
		jp %2
	%elifidni %1, SIGNED
		js %2
	%elifidni %1, OVERFLOW
		jo %2
	%elifidni %1, !CARRY
		jnc %2
	%elifidni %1, !BELOW
		jnb %2
	%elifidni %1, !ABOVE
		jna %2
	%elifidni %1, !PARITY
		jnp %2
	%elifidni %1, !SIGNED
		jns %2
	%elifidni %1, !OVERFLOW
		jno %2
	%endif
%endmacro



;//////////////////////////////////////////////////////////////////////////////
;//
;// The following macros provide a convenient way
;// to simulate high level constructs.  They allow
;// nesting of statements of arbitrary depth.
;// Note that the address labels generated are dot-
;// prepended to not break NASMX locals!

%imacro IF 3.nolist
%push __NX_CTX_IF__
	; we must obtain any outer context label sequence
	; to enable the break macro to succeed.
	%ifndef __NX_OPER_LABEL_SEQ__
		%xdefine __NX_OPER_LABEL_SEQ__ 0
	%endif
	%assign %$__nx_oper_label_seq %[__NX_OPER_LABEL_SEQ__]
	; sequence label numbers for the IF macro must be
	; separate from looping sequence label numbers.
	%ifndef __NX_OPER_IF_LABEL_SEQ__
		%xdefine __NX_OPER_IF_LABEL_SEQ__ 0
	%endif
	%assign %$__nx_oper_if_label_seq %[__NX_OPER_IF_LABEL_SEQ__] + 1
	%undef __NX_OPER_IF_LABEL_SEQ__
	%xdefine __NX_OPER_IF_LABEL_SEQ__ %[%$__nx_oper_if_label_seq]

	%assign %$__nx_oper_else 0
	%assign %$__nx_oper_if_label_next 1
	cmp %1, %3
	RJMP %2, .__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]
%endmacro


%imacro ELSIF 3.nolist
	%ifctx __NX_CTX_IF__
		%if %$__nx_oper_else > 0
			%error "ELSIF cannot follow ELSE block."
		%endif
		jmp .__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]
		.__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]:
		%assign %$__nx_oper_if_label_next 1+%$__nx_oper_if_label_next
		cmp %1, %3
		RJMP %2, .__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]
	%else
		%error "ELSIF directive must be within an IF block."
	%endif
%endmacro


%imacro ELSE 0.nolist
	%ifctx __NX_CTX_IF__
		%if %$__nx_oper_else > 0
			%error "There can only be one ELSE per IF block."
		%else
			%assign %$__nx_oper_else 1
			jmp .__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]
			.__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]:
			%assign %$__nx_oper_if_label_next 1+%$__nx_oper_if_label_next
		%endif
	%else
		%error "ELSE directive must be within an IF block."
	%endif
%endmacro


%imacro ENDIF 0.nolist
	%ifctx __NX_CTX_IF__
		; must have a forward label in case elsif/else macros used.
		.__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]:
		.__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]:
		%pop
	%else
		%error "ENDIF directive must be within an IF block."
	%endif
%endmacro


%imacro BREAK 0.nolist
	jmp .__NX_OPER_LABEL_EXIT_%[%$__nx_oper_label_seq]
%endmacro


%imacro CONTINUE 0.nolist
	jmp .__NX_OPER_LABEL_CONTINUE_%[%$__nx_oper_label_seq]
%endmacro


%imacro SWITCH 1.nolist
%push __NX_CTX_SWITCH__
	%ifndef __NX_OPER_LABEL_SEQ__
		%xdefine __NX_OPER_LABEL_SEQ__ 0
	%endif
	%assign %$__nx_oper_label_seq %[__NX_OPER_LABEL_SEQ__] + 1
	%undef __NX_OPER_LABEL_SEQ__
	%xdefine __NX_OPER_LABEL_SEQ__ %[%$__nx_oper_label_seq]
	%ifnidni __AX, %1
		mov __AX, %1
	%endif
	%assign %$__nx_oper_label_next 1
	%assign %$__nx_oper_default 0
%endmacro


%imacro CASE 1.nolist
	%ifctx __NX_CTX_SWITCH__
		%if %$__nx_oper_default > 0
			%error "CASE must appear before DEFAULT in SWITCH block."
		%endif
		.__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]:
		%assign %$__nx_oper_label_next 1+%$__nx_oper_label_next
		cmp __AX, %1
		jnz near .__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]
	%else
		%error "CASE directive must be within a SWITCH block."
	%endif
%endmacro


%imacro DEFAULT 0.nolist
	%ifctx __NX_CTX_SWITCH__
		%if %$__nx_oper_default > 0
			%error "There can only be one DEFAULT per SWITCH block."
		%endif
		%assign %$__nx_oper_default 1
		.__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]:
		%assign %$__nx_oper_label_next 1+%$__nx_oper_label_next
	%else
		%error "DEFAULT directive must be within a SWITCH block."
	%endif
%endmacro


%imacro ENDSWITCH 0.nolist
	%ifctx __NX_CTX_SWITCH__
		.__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]:
		.__NX_OPER_LABEL_EXIT_%[%$__nx_oper_label_seq]:
		%pop
	%else
		%error "Missing SWITCH directive."
	%endif
%endmacro


%imacro REPEAT 0.nolist
%push __NX_CTX_REPEAT__
	%ifndef __NX_OPER_LABEL_SEQ__
		%xdefine __NX_OPER_LABEL_SEQ__ 0
	%endif
	%assign %$__nx_oper_label_seq %[__NX_OPER_LABEL_SEQ__] + 1
	%undef __NX_OPER_LABEL_SEQ__
	%xdefine __NX_OPER_LABEL_SEQ__ %[%$__nx_oper_label_seq]
	%assign %$__nx_oper_label_next 1
	.__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]:
%endmacro


%imacro UNTIL 3.nolist
	%ifctx __NX_CTX_REPEAT__
		.__NX_OPER_LABEL_CONTINUE_%[%$__nx_oper_label_seq]:
		cmp %1, %3
		RJMP %2, .__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]
		.__NX_OPER_LABEL_EXIT_%[%$__nx_oper_label_seq]:
		%pop
	%elifctx __NX_CTX_DO__
		%warning "DO/UNTIL combination is deprecated.  Use REPEAT/UNTIL."
		.__NX_OPER_LABEL_CONTINUE_%[%$__nx_oper_label_seq]:
		cmp %1, %3
		RJMP %2, .__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]
		.__NX_OPER_LABEL_EXIT_%[%$__nx_oper_label_seq]:
		%pop
	%else
		%error "Missing REPEAT directive."
	%endif
%endmacro


%imacro DO 0.nolist
%push __NX_CTX_DO__
	%ifndef __NX_OPER_LABEL_SEQ__
		%xdefine __NX_OPER_LABEL_SEQ__ 0
	%endif
	%assign %$__nx_oper_label_seq %[__NX_OPER_LABEL_SEQ__] + 1
	%undef __NX_OPER_LABEL_SEQ__
	%xdefine __NX_OPER_LABEL_SEQ__ %[%$__nx_oper_label_seq]
	%assign %$__nx_oper_label_next 1
	.__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]:
%endmacro


; There is some trickery with this macro: If the DO context exists we assume
; that this is a finishing while statement; If no DO context is found we assume
; that the user is beginning a while loop.  This implies that you cannot use a
; WHILE loop directly inside a DO loop without some other intervening context.
; If your code requires this then you must use REPEAT/UNTIL for the outer loop.
%imacro WHILE 3.nolist
	%ifctx __NX_CTX_DO__
		.__NX_OPER_LABEL_CONTINUE_%[%$__nx_oper_label_seq]:
		cmp %1, %3
		SJMP %2, .__NX_OPER_LABEL_%[%$__nx_oper_label_seq]_%[%$__nx_oper_label_next]
		.__NX_OPER_LABEL_EXIT_%[%$__nx_oper_label_seq]:
		%pop
	%else
		%push __NX_CTX_WHILE__
		%ifndef __NX_OPER_LABEL_SEQ__
			%xdefine __NX_OPER_LABEL_SEQ__ 0
		%endif
		%assign %$__nx_oper_label_seq %[__NX_OPER_LABEL_SEQ__] + 1
		%undef __NX_OPER_LABEL_SEQ__
		%xdefine __NX_OPER_LABEL_SEQ__ %[%$__nx_oper_label_seq]
		%assign %$__nx_oper_label_next 1
		.__NX_OPER_LABEL_CONTINUE_%[%$__nx_oper_label_seq]:
		cmp %1, %3
		RJMP %2, .__NX_OPER_LABEL_EXIT_%[%$__nx_oper_label_seq]
	%endif
%endmacro


%imacro ENDWHILE 0.nolist
	%ifctx __NX_CTX_WHILE__
		jmp .__NX_OPER_LABEL_CONTINUE_%[%$__nx_oper_label_seq]
		.__NX_OPER_LABEL_EXIT_%[%$__nx_oper_label_seq]:
		%pop
	%else
		%error "Missing WHILE directive."
	%endif
%endmacro


;// The following is used to wrap test code when debugging
;%define __NX_DEBUG__  ;;//// * * * BEGIN NASMX DEBUG FRAME * * * ///////////////
%ifdef __NX_DEBUG__

%xdefine __NX_DEBUG_SOURCE_LINE_START__ __LINE__

;;// * * PLACE TEST CODE HERE * *

%xdefine __NX_DEBUG_SOURCE_LINE_END__ __LINE__
%ifndef __NX_DEBUG_SOURCE_LINE_START__
   %fatal NXDEBUG: BREAK line: __LINE__ section(????,__NX_DEBUG_SOURCE_LINE_END__) __NX_DEBUG_SOURCE_LINE_START__ undefined!
%endif
%assign __NX_DEBUG_SOURCE_LINE_COUNT__ __NX_DEBUG_SOURCE_LINE_END__ - __NX_DEBUG_SOURCE_LINE_START__
%fatal NXDEBUG: BREAK line: __LINE__ section(__NX_DEBUG_SOURCE_LINE_START__,__NX_DEBUG_SOURCE_LINE_END__) __NX_DEBUG_SOURCE_LINE_COUNT__ lines
%endif  ;;///////////////// * * * END NASMX DEBUG FRAME * * * /////////////////

%endif	; ifndef __NASMX_INCLUDED__
